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,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logger = void 0;
7
+ exports.setVerbose = setVerbose;
8
+ const picocolors_1 = __importDefault(require("picocolors"));
9
+ let verboseEnabled = false;
10
+ function setVerbose(v) {
11
+ verboseEnabled = v;
12
+ }
13
+ exports.logger = {
14
+ info(msg) {
15
+ console.log(picocolors_1.default.cyan('[info] ') + msg);
16
+ },
17
+ success(msg) {
18
+ console.log(picocolors_1.default.green('[ok] ') + msg);
19
+ },
20
+ warn(msg) {
21
+ console.warn(picocolors_1.default.yellow('[warn] ') + msg);
22
+ },
23
+ error(msg) {
24
+ console.error(picocolors_1.default.red('[err] ') + msg);
25
+ },
26
+ debug(msg) {
27
+ if (verboseEnabled) {
28
+ console.log(picocolors_1.default.gray('[dbg] ') + picocolors_1.default.gray(msg));
29
+ }
30
+ },
31
+ plain(msg) {
32
+ console.log(msg);
33
+ },
34
+ section(title) {
35
+ console.log('');
36
+ console.log(picocolors_1.default.bold(picocolors_1.default.white('>> ' + title)));
37
+ },
38
+ /**
39
+ * Print a styled configuration box (like Claude Code style)
40
+ */
41
+ configBox(title, items) {
42
+ // Calculate max label width for alignment
43
+ const maxLabelWidth = Math.max(...items.map(item => item.label.length));
44
+ const boxWidth = Math.max(60, maxLabelWidth + 40);
45
+ console.log('');
46
+ console.log(picocolors_1.default.bold(picocolors_1.default.cyan('╭─ ' + title + ' ' + '─'.repeat(Math.max(0, boxWidth - title.length - 3)))));
47
+ for (const item of items) {
48
+ const label = picocolors_1.default.bold(picocolors_1.default.white(item.label));
49
+ const paddedLabel = label + ' '.repeat(Math.max(0, maxLabelWidth - item.label.length));
50
+ const value = picocolors_1.default.cyan(item.value);
51
+ console.log(`│ ${paddedLabel} ${value}`);
52
+ }
53
+ console.log(picocolors_1.default.bold(picocolors_1.default.cyan('╰' + '─'.repeat(boxWidth + 2))));
54
+ console.log('');
55
+ },
56
+ };
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.detectBaselineMode = detectBaselineMode;
7
+ exports.validateArgs = validateArgs;
8
+ exports.listSupportedArches = listSupportedArches;
9
+ exports.listSupportedAgents = listSupportedAgents;
10
+ const fs_extra_1 = __importDefault(require("fs-extra"));
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const SUPPORTED_ARCHES = [
13
+ 'android-compose',
14
+ 'android-xml',
15
+ 'cpp',
16
+ 'web-react',
17
+ 'python',
18
+ ];
19
+ const SUPPORTED_AGENTS = [
20
+ 'codechat',
21
+ 'qoder',
22
+ 'cursor',
23
+ 'claude-code',
24
+ 'generic',
25
+ ];
26
+ const NAME_RE = /^[a-z][a-z0-9-]{1,39}$/;
27
+ const DEFAULT_BASELINE_MAX_FILE_KB = 1024;
28
+ /**
29
+ * Decide whether the `--baseline` value looks like a git remote or a local path.
30
+ * Heuristics (ordered):
31
+ * - ssh-style: git@host:path
32
+ * - ssh scheme: ssh://...
33
+ * - http(s) ending with .git
34
+ * - ends with .git
35
+ * - http(s) URL whose host matches a known git hosting provider
36
+ * Otherwise treated as a local path.
37
+ */
38
+ function detectBaselineMode(input) {
39
+ const v = input.trim();
40
+ if (/^git@[^:]+:.+/i.test(v))
41
+ return 'git';
42
+ if (/^ssh:\/\//i.test(v))
43
+ return 'git';
44
+ if (/^git:\/\//i.test(v))
45
+ return 'git';
46
+ if (/^https?:\/\/.+\.git$/i.test(v))
47
+ return 'git';
48
+ if (/\.git$/i.test(v) && /^(https?|ssh|git):\/\//i.test(v))
49
+ return 'git';
50
+ if (/^https?:\/\//i.test(v) &&
51
+ /(github\.com|gitlab\.com|gitee\.com|bitbucket\.org|codehub\.|coding\.net|dev\.azure\.com)/i.test(v)) {
52
+ return 'git';
53
+ }
54
+ return 'local';
55
+ }
56
+ function validateArgs(input) {
57
+ const errors = [];
58
+ // name
59
+ if (!input.name) {
60
+ errors.push('--name is required');
61
+ }
62
+ else if (!NAME_RE.test(input.name)) {
63
+ errors.push(`--name "${input.name}" is invalid. Allowed: lowercase letters, digits, hyphen; start with letter; length 2-40.`);
64
+ }
65
+ // arch
66
+ if (!input.arch) {
67
+ errors.push('--arch is required');
68
+ }
69
+ else if (!SUPPORTED_ARCHES.includes(input.arch)) {
70
+ errors.push(`--arch "${input.arch}" is not supported. Allowed: ${SUPPORTED_ARCHES.join(', ')}`);
71
+ }
72
+ // agent
73
+ if (!input.agent) {
74
+ errors.push('--agent is required');
75
+ }
76
+ else if (!SUPPORTED_AGENTS.includes(input.agent)) {
77
+ errors.push(`--agent "${input.agent}" is not supported. Allowed: ${SUPPORTED_AGENTS.join(', ')}`);
78
+ }
79
+ // baseline (optional) + mode detection
80
+ let baselineValue;
81
+ let baselineMode;
82
+ if (input.baseline) {
83
+ baselineMode = detectBaselineMode(input.baseline);
84
+ if (baselineMode === 'local') {
85
+ const abs = node_path_1.default.resolve(input.baseline);
86
+ if (!fs_extra_1.default.existsSync(abs)) {
87
+ errors.push(`--baseline path does not exist: ${abs}`);
88
+ }
89
+ else if (!fs_extra_1.default.statSync(abs).isDirectory()) {
90
+ errors.push(`--baseline must be a directory: ${abs}`);
91
+ }
92
+ baselineValue = abs;
93
+ }
94
+ else {
95
+ // git mode: keep raw URL
96
+ baselineValue = input.baseline.trim();
97
+ }
98
+ }
99
+ // baseline-branch only meaningful in git mode; silently accepted otherwise
100
+ // (caller will warn if user passed it in local mode)
101
+ const baselineBranch = baselineMode === 'git' && input.baselineBranch
102
+ ? input.baselineBranch.trim() || undefined
103
+ : undefined;
104
+ // baseline-max-file-kb
105
+ let maxSize = DEFAULT_BASELINE_MAX_FILE_KB;
106
+ if (typeof input.baselineMaxFileKB === 'number' && Number.isFinite(input.baselineMaxFileKB)) {
107
+ if (input.baselineMaxFileKB <= 0) {
108
+ errors.push('--baseline-max-file-kb must be a positive number (KB)');
109
+ }
110
+ else {
111
+ maxSize = Math.floor(input.baselineMaxFileKB);
112
+ }
113
+ }
114
+ if (errors.length > 0) {
115
+ throw new Error('Argument validation failed:\n - ' + errors.join('\n - '));
116
+ }
117
+ return {
118
+ name: input.name,
119
+ arch: input.arch,
120
+ agent: input.agent,
121
+ baseline: baselineValue,
122
+ baselineMode,
123
+ baselineBranch,
124
+ baselineMaxFileKB: maxSize,
125
+ };
126
+ }
127
+ function listSupportedArches() {
128
+ return SUPPORTED_ARCHES;
129
+ }
130
+ function listSupportedAgents() {
131
+ return SUPPORTED_AGENTS;
132
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getCliVersion = getCliVersion;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ let cachedVersion = null;
10
+ function getCliVersion() {
11
+ if (cachedVersion)
12
+ return cachedVersion;
13
+ // __dirname at runtime is dist/utils, so package.json lives two levels up.
14
+ const pkgPath = node_path_1.default.resolve(__dirname, '..', '..', 'package.json');
15
+ try {
16
+ const pkg = fs_extra_1.default.readJsonSync(pkgPath);
17
+ cachedVersion = String(pkg.version || '0.0.0');
18
+ }
19
+ catch {
20
+ cachedVersion = '0.0.0';
21
+ }
22
+ return cachedVersion;
23
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /**
3
+ * AbortSignal-based cancellation helpers for the wiki core.
4
+ * Replaces VS Code's `CancellationToken` / `CancellationError` so the core can
5
+ * run in plain Node (CLI / CI) without an IDE host.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.WikiAbortError = exports.WIKI_ABORT_ERROR_NAME = void 0;
9
+ exports.assertNotAborted = assertNotAborted;
10
+ exports.isAbortError = isAbortError;
11
+ exports.WIKI_ABORT_ERROR_NAME = "AbortError";
12
+ /** Thrown when a wiki run is aborted by the caller (e.g. SIGINT / Ctrl+C). */
13
+ class WikiAbortError extends Error {
14
+ constructor(message = "Aborted") {
15
+ super(message);
16
+ this.name = exports.WIKI_ABORT_ERROR_NAME;
17
+ }
18
+ }
19
+ exports.WikiAbortError = WikiAbortError;
20
+ function assertNotAborted(signal) {
21
+ if (signal.aborted)
22
+ throw new WikiAbortError();
23
+ }
24
+ /** True when an error (or its cause) represents an abort, including fetch's DOMException. */
25
+ function isAbortError(e) {
26
+ if (!e || typeof e !== "object")
27
+ return false;
28
+ const name = e.name;
29
+ return name === exports.WIKI_ABORT_ERROR_NAME;
30
+ }
@@ -0,0 +1,79 @@
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.resolveWikiRunConfig = resolveWikiRunConfig;
37
+ exports.loadRepowikiMetadata = loadRepowikiMetadata;
38
+ const fs = __importStar(require("fs/promises"));
39
+ const path = __importStar(require("path"));
40
+ const envLoader_1 = require("./envLoader");
41
+ const defaults_1 = require("./defaults");
42
+ /**
43
+ * Priority: CLI flag > process.env (`OPENAI_API_KEY` / `OPENAI_BASE_URL` /
44
+ * `DEEPWIKI_OPENAI_CHAT_MODEL`) > cwd `.env` > bundled defaults.
45
+ */
46
+ async function resolveWikiRunConfig(input) {
47
+ const dot = await (0, envLoader_1.findWorkspaceDotEnv)(input.cwd);
48
+ const apiKey = (input.apiKey ?? "").trim() ||
49
+ (process.env.OPENAI_API_KEY ?? "").trim() ||
50
+ (dot.OPENAI_API_KEY ?? "").trim() ||
51
+ defaults_1.DEFAULT_OPENAI_API_KEY;
52
+ const baseUrl = (input.baseUrl ?? "").trim() ||
53
+ (process.env.OPENAI_BASE_URL ?? "").trim() ||
54
+ (dot.OPENAI_BASE_URL ?? "").trim() ||
55
+ defaults_1.DEFAULT_OPENAI_BASE_URL;
56
+ const model = (input.model ?? "").trim() ||
57
+ (process.env.DEEPWIKI_OPENAI_CHAT_MODEL ?? "").trim() ||
58
+ (dot.DEEPWIKI_OPENAI_CHAT_MODEL ?? "").trim() ||
59
+ defaults_1.DEFAULT_OPENAI_CHAT_MODEL;
60
+ return { baseUrl, apiKey, model };
61
+ }
62
+ /**
63
+ * Lightweight reader for `<wikiBase>/metadata.json`. Kept separate from the
64
+ * config resolver so it stays tree-shakable for non-CLI consumers.
65
+ */
66
+ async function loadRepowikiMetadata(wikiBaseFs) {
67
+ try {
68
+ const raw = await fs.readFile(path.join(wikiBaseFs, "metadata.json"), "utf8");
69
+ const j = JSON.parse(raw);
70
+ return {
71
+ indexedCommit: j.indexedCommit ?? null,
72
+ sourceRootFs: j.sourceRootFs,
73
+ files: j.files && typeof j.files === "object" ? j.files : undefined,
74
+ };
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ /**
3
+ * Embedded OpenAI-compatible defaults for the wiki core (gateway + chat model).
4
+ * CLI flags / env / .env override these when non-empty.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.DEFAULT_OPENAI_CHAT_MODEL = exports.DEFAULT_OPENAI_API_KEY = exports.DEFAULT_OPENAI_BASE_URL = void 0;
8
+ // export const DEFAULT_OPENAI_BASE_URL = "http://model-api.desaysv.com/v1";
9
+ // export const DEFAULT_OPENAI_API_KEY =
10
+ // "sk-3v4T1keyvRQNSDewOcqq8gJeIS6NZ1Ez8Yo7XoIzUCMgFy9P";
11
+ // //Qwen3.6-27B|deepseek-v4-pro|mimo-v2-pro|glm-5.1
12
+ // export const DEFAULT_OPENAI_CHAT_MODEL = "Qwen3.6-27B";
13
+ exports.DEFAULT_OPENAI_BASE_URL = "https://api.laozhang.ai/v1";
14
+ exports.DEFAULT_OPENAI_API_KEY = "sk-7C1tRtidwPLpDEwY84CbD4E7Ba3f4c36AaF69e9b017aB8F4";
15
+ //claude-haiku-4-5-20251001|deepseek-v4-flash
16
+ exports.DEFAULT_OPENAI_CHAT_MODEL = "deepseek-v4-flash";
@@ -0,0 +1,78 @@
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.loadDotEnvFile = loadDotEnvFile;
37
+ exports.findWorkspaceDotEnv = findWorkspaceDotEnv;
38
+ const fs = __importStar(require("fs/promises"));
39
+ const path = __importStar(require("path"));
40
+ /** Minimal .env parsing (KEY=VALUE, no multiline values). */
41
+ async function loadDotEnvFile(envPath) {
42
+ const raw = await fs.readFile(envPath, "utf8").catch(() => "");
43
+ const out = {};
44
+ for (const line of raw.split(/\r?\n/)) {
45
+ const t = line.trim();
46
+ if (!t || t.startsWith("#"))
47
+ continue;
48
+ const eq = t.indexOf("=");
49
+ if (eq < 1)
50
+ continue;
51
+ const k = t.slice(0, eq).trim();
52
+ let v = t.slice(eq + 1).trim();
53
+ if ((v.startsWith('"') && v.endsWith('"')) ||
54
+ (v.startsWith("'") && v.endsWith("'"))) {
55
+ v = v.slice(1, -1);
56
+ }
57
+ out[k] = v;
58
+ }
59
+ return out;
60
+ }
61
+ /** Search the given directory and up to two parent levels for a `.env` file. */
62
+ async function findWorkspaceDotEnv(workspaceRootFs) {
63
+ const candidates = [
64
+ path.join(workspaceRootFs, ".env"),
65
+ path.join(workspaceRootFs, "..", ".env"),
66
+ path.join(workspaceRootFs, "..", "..", ".env"),
67
+ ];
68
+ for (const p of candidates) {
69
+ try {
70
+ await fs.access(p);
71
+ return await loadDotEnvFile(p);
72
+ }
73
+ catch {
74
+ continue;
75
+ }
76
+ }
77
+ return {};
78
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * svharnessbuild wiki generator — platform-agnostic port of repowiki core.
4
+ *
5
+ * Public entry points:
6
+ * - `runRepowikiIndex(opts)` — generate wiki under `<wikiOutputRootFs>/<wikiRelPath>/`.
7
+ * - `resolveWikiRunConfig(input)` — resolve baseUrl/apiKey/model from CLI > env > .env > defaults.
8
+ * - `WikiAbortError` — thrown when an AbortSignal cancels the run.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.DEFAULT_OPENAI_CHAT_MODEL = exports.DEFAULT_OPENAI_BASE_URL = exports.isAbortError = exports.assertNotAborted = exports.WikiAbortError = exports.loadRepowikiMetadata = exports.resolveWikiRunConfig = exports.writeWikiTasks = exports.langRunForRepowikiTarget = exports.REPOWIKI_LANG_ZH = exports.REPOWIKI_LANG_EN = exports.runRepowikiOutlineOnly = exports.runRepowikiIndex = void 0;
12
+ var repowikiIndexer_1 = require("./repowikiIndexer");
13
+ Object.defineProperty(exports, "runRepowikiIndex", { enumerable: true, get: function () { return repowikiIndexer_1.runRepowikiIndex; } });
14
+ Object.defineProperty(exports, "runRepowikiOutlineOnly", { enumerable: true, get: function () { return repowikiIndexer_1.runRepowikiOutlineOnly; } });
15
+ Object.defineProperty(exports, "REPOWIKI_LANG_EN", { enumerable: true, get: function () { return repowikiIndexer_1.REPOWIKI_LANG_EN; } });
16
+ Object.defineProperty(exports, "REPOWIKI_LANG_ZH", { enumerable: true, get: function () { return repowikiIndexer_1.REPOWIKI_LANG_ZH; } });
17
+ Object.defineProperty(exports, "langRunForRepowikiTarget", { enumerable: true, get: function () { return repowikiIndexer_1.langRunForRepowikiTarget; } });
18
+ var wikiTasksWriter_1 = require("./wikiTasksWriter");
19
+ Object.defineProperty(exports, "writeWikiTasks", { enumerable: true, get: function () { return wikiTasksWriter_1.writeWikiTasks; } });
20
+ var config_1 = require("./config");
21
+ Object.defineProperty(exports, "resolveWikiRunConfig", { enumerable: true, get: function () { return config_1.resolveWikiRunConfig; } });
22
+ Object.defineProperty(exports, "loadRepowikiMetadata", { enumerable: true, get: function () { return config_1.loadRepowikiMetadata; } });
23
+ var abort_1 = require("./abort");
24
+ Object.defineProperty(exports, "WikiAbortError", { enumerable: true, get: function () { return abort_1.WikiAbortError; } });
25
+ Object.defineProperty(exports, "assertNotAborted", { enumerable: true, get: function () { return abort_1.assertNotAborted; } });
26
+ Object.defineProperty(exports, "isAbortError", { enumerable: true, get: function () { return abort_1.isAbortError; } });
27
+ var defaults_1 = require("./defaults");
28
+ Object.defineProperty(exports, "DEFAULT_OPENAI_BASE_URL", { enumerable: true, get: function () { return defaults_1.DEFAULT_OPENAI_BASE_URL; } });
29
+ Object.defineProperty(exports, "DEFAULT_OPENAI_CHAT_MODEL", { enumerable: true, get: function () { return defaults_1.DEFAULT_OPENAI_CHAT_MODEL; } });
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.completionTextFromResponse = completionTextFromResponse;
4
+ exports.isFetchAbortError = isFetchAbortError;
5
+ exports.isLikelyNetworkFetchFailure = isLikelyNetworkFetchFailure;
6
+ exports.errorLogTextWithCauseChain = errorLogTextWithCauseChain;
7
+ exports.chatCompletionText = chatCompletionText;
8
+ const NON_JSON_HINT = "Server returned non-JSON or SSE — check OPENAI_BASE_URL supports JSON completions";
9
+ function parseCompletionJson(raw) {
10
+ try {
11
+ return JSON.parse(raw);
12
+ }
13
+ catch {
14
+ throw new Error(NON_JSON_HINT);
15
+ }
16
+ }
17
+ function completionTextFromJson(j) {
18
+ if (j.error?.message) {
19
+ throw new Error(j.error.message);
20
+ }
21
+ const c0 = j.choices?.[0];
22
+ return c0?.message?.content ?? "";
23
+ }
24
+ /** Aggregate `data:` JSON chunks from an SSE (or SSE-shaped) body. */
25
+ function parseSseChatCompletionBody(body) {
26
+ let aggregated = "";
27
+ for (const line of body.split(/\r?\n/)) {
28
+ const trimmed = line.trimStart();
29
+ if (!trimmed.startsWith("data:")) {
30
+ continue;
31
+ }
32
+ const payload = trimmed.slice(5).trimStart();
33
+ if (payload === "" || payload === "[DONE]") {
34
+ continue;
35
+ }
36
+ let j;
37
+ try {
38
+ j = JSON.parse(payload);
39
+ }
40
+ catch {
41
+ throw new Error(NON_JSON_HINT);
42
+ }
43
+ if (j.error?.message) {
44
+ throw new Error(j.error.message);
45
+ }
46
+ const c0 = j.choices?.[0];
47
+ const piece = c0?.message?.content ?? c0?.delta?.content ?? "";
48
+ aggregated += piece;
49
+ }
50
+ return aggregated;
51
+ }
52
+ function responseLooksLikeSse(res, rawBody) {
53
+ const ct = (res.headers.get("content-type") ?? "").toLowerCase();
54
+ if (ct.includes("text/event-stream")) {
55
+ return true;
56
+ }
57
+ return rawBody.trimStart().startsWith("data:");
58
+ }
59
+ async function completionTextFromResponse(res) {
60
+ let raw;
61
+ try {
62
+ raw = await res.text();
63
+ }
64
+ catch (e) {
65
+ throw new Error(`${NON_JSON_HINT} (${String(e)})`);
66
+ }
67
+ const text = responseLooksLikeSse(res, raw)
68
+ ? parseSseChatCompletionBody(raw)
69
+ : completionTextFromJson(parseCompletionJson(raw));
70
+ if (!text.trim()) {
71
+ throw new Error("Empty completion from chat API");
72
+ }
73
+ return text;
74
+ }
75
+ /** True when `fetch` rejected because the request was aborted (user cancel / AbortSignal). */
76
+ function isFetchAbortError(e) {
77
+ if (!e || typeof e !== "object")
78
+ return false;
79
+ const name = e.name;
80
+ return name === "AbortError";
81
+ }
82
+ const MSG_OPENAI_NETWORK_ZH = "无法连接到 API 服务器。请检查网络、VPN、防火墙或公司代理;并确认设置里的 OpenAI 兼容地址(--wiki-base-url / OPENAI_BASE_URL)正确且服务已启动。";
83
+ const MSG_OPENAI_FETCH_OTHER_ZH = "OpenAI 兼容接口请求未成功。请检查 API 地址、密钥与网络环境;技术详情已写入日志。";
84
+ function errnoCodesInCauseChain(e) {
85
+ const codes = [];
86
+ let cur = e;
87
+ let depth = 0;
88
+ while (cur && depth < 10) {
89
+ if (typeof cur === "object" && cur !== null && "code" in cur) {
90
+ const c = cur.code;
91
+ if (typeof c === "string")
92
+ codes.push(c);
93
+ }
94
+ cur = cur instanceof Error ? cur.cause : undefined;
95
+ depth++;
96
+ }
97
+ return codes;
98
+ }
99
+ function causeChainMessagesLower(e) {
100
+ const parts = [];
101
+ let cur = e;
102
+ let depth = 0;
103
+ while (cur && depth < 10) {
104
+ if (cur instanceof Error) {
105
+ parts.push(cur.message);
106
+ cur = cur.cause;
107
+ }
108
+ else {
109
+ parts.push(String(cur));
110
+ break;
111
+ }
112
+ depth++;
113
+ }
114
+ return parts.join(" ").toLowerCase();
115
+ }
116
+ /** True when `fetch` likely failed due to DNS, TCP, TLS, timeout, or proxy (not HTTP 4xx/5xx). */
117
+ function isLikelyNetworkFetchFailure(e) {
118
+ const blob = causeChainMessagesLower(e);
119
+ if (blob.includes("fetch failed"))
120
+ return true;
121
+ if (blob.includes("network error when attempting to fetch resource"))
122
+ return true;
123
+ const netCodes = new Set([
124
+ "ECONNREFUSED",
125
+ "ENOTFOUND",
126
+ "ETIMEDOUT",
127
+ "EAI_AGAIN",
128
+ "ECONNRESET",
129
+ "ECONNABORTED",
130
+ "ENETUNREACH",
131
+ "EHOSTUNREACH",
132
+ "CERT_HAS_EXPIRED",
133
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
134
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
135
+ "SELF_SIGNED_CERT_IN_CHAIN",
136
+ "EPROTO",
137
+ ]);
138
+ for (const code of errnoCodesInCauseChain(e)) {
139
+ if (netCodes.has(code))
140
+ return true;
141
+ if (code.startsWith("UND_ERR_"))
142
+ return true;
143
+ }
144
+ return false;
145
+ }
146
+ function httpFailureUserMessage(status, statusText) {
147
+ return `API 返回错误(HTTP ${status}${statusText ? ` ${statusText}` : ""})。请确认服务可用、模型名称与 API 密钥是否正确。`;
148
+ }
149
+ /** Full text for logs, including `error.cause` chain (errno codes when present). */
150
+ function errorLogTextWithCauseChain(e) {
151
+ if (!(e instanceof Error))
152
+ return String(e);
153
+ const lines = [e.message];
154
+ let cur = e.cause;
155
+ let depth = 0;
156
+ while (cur != null && depth < 12) {
157
+ if (cur instanceof Error) {
158
+ let line = cur.message;
159
+ const code = cur.code;
160
+ if (typeof code === "string")
161
+ line += ` [${code}]`;
162
+ lines.push(line);
163
+ cur = cur.cause;
164
+ }
165
+ else {
166
+ lines.push(String(cur));
167
+ break;
168
+ }
169
+ depth++;
170
+ }
171
+ return lines.join("\n");
172
+ }
173
+ async function chatCompletionText(params) {
174
+ const base = params.baseUrl.replace(/\/+$/, "");
175
+ const url = `${base}/chat/completions`;
176
+ const headers = {
177
+ "Content-Type": "application/json",
178
+ Accept: "application/json",
179
+ Authorization: `Bearer ${params.apiKey}`,
180
+ };
181
+ const body = JSON.stringify({
182
+ model: params.model,
183
+ messages: params.messages,
184
+ temperature: params.temperature ?? 0.3,
185
+ stream: false,
186
+ });
187
+ let res;
188
+ try {
189
+ res = await fetch(url, { method: "POST", headers, body, signal: params.signal });
190
+ }
191
+ catch (e) {
192
+ if (params.signal?.aborted || isFetchAbortError(e)) {
193
+ throw e;
194
+ }
195
+ const chain = e instanceof Error ? errorLogTextWithCauseChain(e) : String(e);
196
+ const technical = `POST ${url}\n${chain}`;
197
+ if (isLikelyNetworkFetchFailure(e)) {
198
+ throw new Error(MSG_OPENAI_NETWORK_ZH, { cause: technical });
199
+ }
200
+ throw new Error(MSG_OPENAI_FETCH_OTHER_ZH, { cause: technical });
201
+ }
202
+ if (params.signal?.aborted) {
203
+ const err = new Error("Aborted");
204
+ err.name = "AbortError";
205
+ throw err;
206
+ }
207
+ if (!res.ok) {
208
+ const t = await res.text().catch(() => "");
209
+ const technical = `OpenAI-compat ${res.status} ${res.statusText}: ${t.slice(0, 600)}`;
210
+ throw new Error(httpFailureUserMessage(res.status, res.statusText), { cause: technical });
211
+ }
212
+ const text = await completionTextFromResponse(res);
213
+ if (params.signal?.aborted) {
214
+ const err = new Error("Aborted");
215
+ err.name = "AbortError";
216
+ throw err;
217
+ }
218
+ return text;
219
+ }