svharness 0.15.11 → 0.15.13
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/README.md +106 -2
- package/auto/auto-harness-detail-design.md +136 -4
- package/auto/skills/svharness/SKILL.md +44 -1
- package/auto/templates/auto-pack-req.config.example.yaml +29 -0
- package/auto/templates/auto.config.example.yaml +1 -1
- package/auto/templates/phase-prompts/S40-adversarial-review.md +31 -0
- package/auto/templates/phase-prompts/S40-review.md +22 -0
- package/auto/templates/phase-prompts/S40-sample-trace.md +26 -0
- package/auto/templates/requirements-review-rubric.yaml +79 -0
- package/dist/commands/auto-pack-req.js +70 -0
- package/dist/commands/auto.js +16 -1
- package/dist/commands/convert.js +2 -0
- package/dist/commands/shell-integration.js +29 -56
- package/dist/config/merge-options.js +2 -0
- package/dist/config/normalize.js +7 -0
- package/dist/constants/convert.js +5 -0
- package/dist/core/markitdown-client.js +7 -2
- package/dist/index.js +77 -5
- package/dist/lib/acp-agent-cli-resolver.js +193 -0
- package/dist/lib/acp-client.js +4 -2
- package/dist/lib/agent-launcher.js +9 -4
- package/dist/lib/auto-assets.js +1 -0
- package/dist/lib/auto-optimize.js +23 -3
- package/dist/lib/auto-orchestrator.js +53 -20
- package/dist/lib/auto-pack-req-context.js +88 -0
- package/dist/lib/auto-pack-req-finalize.js +28 -0
- package/dist/lib/auto-req-pack-review.js +161 -0
- package/dist/lib/auto-sample-trace.js +144 -0
- package/dist/lib/auto-state.js +124 -15
- package/dist/lib/gate-checker.js +20 -10
- package/dist/lib/phase-runner.js +13 -2
- package/dist/lib/ps-codechat-alias.js +29 -16
- package/dist/lib/review-parser.js +14 -0
- package/dist/lib/score-aggregator.js +21 -0
- package/dist/lib/win-registry.js +1 -1
- package/dist/utils/validate-args.js +2 -1
- package/package.json +3 -2
- package/templates/codechat/Start-CodeChat.ps1 +176 -135
- package/templates/codechat/bash.exe.stackdump +29 -0
- package/templates/codechat/docs/project-structure.md +59 -0
- package/templates/svharness.config.example.yaml +2 -0
- package/dist/lib/launch-script-path.js +0 -24
- package/templates/codechat/.claude/.env +0 -59
package/dist/lib/auto-state.js
CHANGED
|
@@ -4,6 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.dedupePhases = dedupePhases;
|
|
7
|
+
exports.dedupePhaseFields = dedupePhaseFields;
|
|
8
|
+
exports.repairBuildStateYaml = repairBuildStateYaml;
|
|
9
|
+
exports.quoteUnsafeNextAction = quoteUnsafeNextAction;
|
|
7
10
|
exports.readBuildState = readBuildState;
|
|
8
11
|
exports.writeBuildState = writeBuildState;
|
|
9
12
|
exports.phaseStatus = phaseStatus;
|
|
@@ -60,29 +63,135 @@ function dedupePhases(rawYaml) {
|
|
|
60
63
|
}
|
|
61
64
|
return result.join('\n');
|
|
62
65
|
}
|
|
66
|
+
const PHASE_FIELD_REGEX = /^ ([A-Za-z_][\w-]*):/;
|
|
67
|
+
/**
|
|
68
|
+
* Within each phase block, drop duplicate field keys (e.g. a second
|
|
69
|
+
* `completed_at:` appended by ACP text-editing). Keeps the **last**
|
|
70
|
+
* occurrence so the most recent agent edit wins.
|
|
71
|
+
*/
|
|
72
|
+
function dedupeFieldsInPhaseBlock(blockLines) {
|
|
73
|
+
if (blockLines.length === 0)
|
|
74
|
+
return blockLines;
|
|
75
|
+
const spans = [];
|
|
76
|
+
for (let i = 0; i < blockLines.length; i++) {
|
|
77
|
+
const match = blockLines[i].match(PHASE_FIELD_REGEX);
|
|
78
|
+
if (!match)
|
|
79
|
+
continue;
|
|
80
|
+
if (spans.length > 0)
|
|
81
|
+
spans[spans.length - 1].end = i;
|
|
82
|
+
spans.push({ key: match[1], start: i, end: blockLines.length });
|
|
83
|
+
}
|
|
84
|
+
const lastByKey = new Map();
|
|
85
|
+
spans.forEach((span, idx) => lastByKey.set(span.key, idx));
|
|
86
|
+
const out = [];
|
|
87
|
+
spans.forEach((span, idx) => {
|
|
88
|
+
if (lastByKey.get(span.key) === idx) {
|
|
89
|
+
out.push(...blockLines.slice(span.start, span.end));
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Strip duplicate field keys inside each phase block under `phases:`.
|
|
96
|
+
*/
|
|
97
|
+
function dedupePhaseFields(rawYaml) {
|
|
98
|
+
const lines = rawYaml.split('\n');
|
|
99
|
+
const phaseKeyRegex = /^ (\S+):$/;
|
|
100
|
+
const result = [];
|
|
101
|
+
let inPhases = false;
|
|
102
|
+
let phaseHeader = null;
|
|
103
|
+
let blockLines = [];
|
|
104
|
+
const flushPhase = () => {
|
|
105
|
+
if (phaseHeader === null)
|
|
106
|
+
return;
|
|
107
|
+
result.push(phaseHeader);
|
|
108
|
+
result.push(...dedupeFieldsInPhaseBlock(blockLines));
|
|
109
|
+
phaseHeader = null;
|
|
110
|
+
blockLines = [];
|
|
111
|
+
};
|
|
112
|
+
for (const line of lines) {
|
|
113
|
+
if (/^phases:$/.test(line)) {
|
|
114
|
+
inPhases = true;
|
|
115
|
+
result.push(line);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (!inPhases) {
|
|
119
|
+
result.push(line);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (/^\S/.test(line) && !/^ /.test(line)) {
|
|
123
|
+
flushPhase();
|
|
124
|
+
inPhases = false;
|
|
125
|
+
result.push(line);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const keyMatch = line.match(phaseKeyRegex);
|
|
129
|
+
if (keyMatch) {
|
|
130
|
+
flushPhase();
|
|
131
|
+
phaseHeader = line;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (phaseHeader !== null) {
|
|
135
|
+
blockLines.push(line);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
result.push(line);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
flushPhase();
|
|
142
|
+
return result.join('\n');
|
|
143
|
+
}
|
|
144
|
+
/** Apply all text-level repairs for agent-corrupted build-state YAML. */
|
|
145
|
+
function repairBuildStateYaml(raw) {
|
|
146
|
+
return quoteUnsafeNextAction(dedupePhaseFields(dedupePhases(raw)));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Quote unquoted next_action scalars that contain colons.
|
|
150
|
+
* Agent text-edits sometimes write "H1: xxx" without quotes, which breaks YAML.
|
|
151
|
+
*/
|
|
152
|
+
function quoteUnsafeNextAction(rawYaml) {
|
|
153
|
+
return rawYaml.replace(/^next_action:\s+(?!['">|])(.+)$/gm, (_match, value) => {
|
|
154
|
+
const trimmed = value.trimEnd();
|
|
155
|
+
if (!trimmed.includes(':')) {
|
|
156
|
+
return _match;
|
|
157
|
+
}
|
|
158
|
+
const escaped = trimmed.replace(/'/g, "''");
|
|
159
|
+
return `next_action: '${escaped}'`;
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function parseBuildStateBody(raw) {
|
|
163
|
+
const body = raw.replace(/^#.*\n/gm, '');
|
|
164
|
+
const state = (js_yaml_1.default.load(body) ?? {});
|
|
165
|
+
state.phases = state.phases ?? {};
|
|
166
|
+
return state;
|
|
167
|
+
}
|
|
168
|
+
async function persistBuildStateRaw(statePath, raw) {
|
|
169
|
+
const tmpPath = statePath + '.tmp';
|
|
170
|
+
await fs_extra_1.default.writeFile(tmpPath, raw, 'utf8');
|
|
171
|
+
await fs_extra_1.default.rename(tmpPath, statePath);
|
|
172
|
+
}
|
|
63
173
|
async function readBuildState(harnessRoot) {
|
|
64
174
|
const statePath = node_path_1.default.join(harnessRoot, '.harness-build-state.yaml');
|
|
65
175
|
const raw = await fs_extra_1.default.readFile(statePath, 'utf8');
|
|
66
|
-
const body = raw.replace(/^#.*\n/gm, '');
|
|
67
176
|
try {
|
|
68
|
-
|
|
69
|
-
state.phases = state.phases ?? {};
|
|
70
|
-
return state;
|
|
177
|
+
return parseBuildStateBody(raw);
|
|
71
178
|
}
|
|
72
179
|
catch (err) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const state = (
|
|
82
|
-
|
|
180
|
+
if (!(err instanceof js_yaml_1.default.YAMLException)) {
|
|
181
|
+
throw err;
|
|
182
|
+
}
|
|
183
|
+
const fixed = repairBuildStateYaml(raw);
|
|
184
|
+
if (fixed === raw) {
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const state = parseBuildStateBody(fixed);
|
|
189
|
+
await persistBuildStateRaw(statePath, fixed);
|
|
83
190
|
return state;
|
|
84
191
|
}
|
|
85
|
-
|
|
192
|
+
catch {
|
|
193
|
+
throw err;
|
|
194
|
+
}
|
|
86
195
|
}
|
|
87
196
|
}
|
|
88
197
|
async function writeBuildState(harnessRoot, state) {
|
package/dist/lib/gate-checker.js
CHANGED
|
@@ -13,10 +13,21 @@ const ESSENTIAL_FILES = [
|
|
|
13
13
|
'AGENTS_BUILD.md',
|
|
14
14
|
'.harness-build-state.yaml',
|
|
15
15
|
];
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const REQ_PACK_ESSENTIAL = [
|
|
17
|
+
'harness.yaml',
|
|
18
|
+
'.harness-build-state.yaml',
|
|
19
|
+
'requirements/raw',
|
|
20
|
+
'requirements/md',
|
|
21
|
+
'requirements/yaml',
|
|
22
|
+
'requirements/_work',
|
|
23
|
+
];
|
|
24
|
+
async function runMechanicalGates(harnessRoot, opts = {}) {
|
|
25
|
+
const normalized = typeof opts === 'boolean' ? { verbose: opts } : opts;
|
|
26
|
+
const scope = normalized.scope ?? 'full';
|
|
27
|
+
const verbose = normalized.verbose ?? false;
|
|
28
|
+
const doctor_exit = await runDoctorGate(harnessRoot, scope);
|
|
18
29
|
const verify_exit = await runVerifyGate(harnessRoot, verbose);
|
|
19
|
-
const file_completeness_pct = await computeFileCompleteness(harnessRoot);
|
|
30
|
+
const file_completeness_pct = await computeFileCompleteness(harnessRoot, scope);
|
|
20
31
|
return {
|
|
21
32
|
doctor_exit,
|
|
22
33
|
verify_exit,
|
|
@@ -24,11 +35,11 @@ async function runMechanicalGates(harnessRoot, verbose = false) {
|
|
|
24
35
|
doctor_passed: doctor_exit === 0,
|
|
25
36
|
};
|
|
26
37
|
}
|
|
27
|
-
async function runDoctorGate(harnessRoot) {
|
|
38
|
+
async function runDoctorGate(harnessRoot, scope) {
|
|
28
39
|
try {
|
|
29
40
|
const report = await (0, index_1.runDoctorChecks)({
|
|
30
41
|
harnessRoot,
|
|
31
|
-
mode: 'pre-seal',
|
|
42
|
+
mode: scope === 'requirements' ? 'requirements' : 'pre-seal',
|
|
32
43
|
strict: true,
|
|
33
44
|
});
|
|
34
45
|
return report.passed ? 0 : 1;
|
|
@@ -48,11 +59,10 @@ async function runVerifyGate(harnessRoot, verbose) {
|
|
|
48
59
|
return 1;
|
|
49
60
|
}
|
|
50
61
|
}
|
|
51
|
-
async function computeFileCompleteness(harnessRoot) {
|
|
52
|
-
const checks =
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
62
|
+
async function computeFileCompleteness(harnessRoot, scope) {
|
|
63
|
+
const checks = scope === 'requirements'
|
|
64
|
+
? [...REQ_PACK_ESSENTIAL]
|
|
65
|
+
: [...ESSENTIAL_FILES, 'requirements', 'references', 'specs', 'agent-env', 'tasks'];
|
|
56
66
|
let present = 0;
|
|
57
67
|
for (const rel of checks) {
|
|
58
68
|
if (await fs_extra_1.default.pathExists(node_path_1.default.join(harnessRoot, rel)))
|
package/dist/lib/phase-runner.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.PhaseRunner = exports.PHASE_DEFS = void 0;
|
|
6
|
+
exports.PhaseRunner = exports.SCOPE_PHASES = exports.PHASE_DEFS = void 0;
|
|
7
7
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
9
|
const logger_1 = require("../utils/logger");
|
|
@@ -28,6 +28,10 @@ exports.PHASE_DEFS = [
|
|
|
28
28
|
{ key: 'S70_runtime_assets', short: 'S70', mode: 'acp', promptTemplate: 'S70-runtime-assets.md' },
|
|
29
29
|
{ key: 'S80_seed_memory', short: 'S80', mode: 'acp', promptTemplate: 'S80-seed-memory.md' },
|
|
30
30
|
];
|
|
31
|
+
exports.SCOPE_PHASES = {
|
|
32
|
+
full: null,
|
|
33
|
+
requirements: ['S30_convert_docs', 'S40_extract_requirements'],
|
|
34
|
+
};
|
|
31
35
|
/** 阶段描述映射,供阶段执行时显示给用户了解当前进展。 */
|
|
32
36
|
const PHASE_DESC = {
|
|
33
37
|
S10_wiki: '生成 baseline wiki 正文',
|
|
@@ -62,7 +66,14 @@ class PhaseRunner {
|
|
|
62
66
|
async getBuildPhases() {
|
|
63
67
|
const harnessRoot = this.ctx.harnessRoot;
|
|
64
68
|
const state = await (0, auto_state_1.readBuildState)(harnessRoot);
|
|
65
|
-
|
|
69
|
+
const allowed = exports.SCOPE_PHASES[this.ctx.scope];
|
|
70
|
+
return exports.PHASE_DEFS.filter((def) => {
|
|
71
|
+
if (!(def.key in state.phases))
|
|
72
|
+
return false;
|
|
73
|
+
if (allowed && !allowed.includes(def.key))
|
|
74
|
+
return false;
|
|
75
|
+
return true;
|
|
76
|
+
});
|
|
66
77
|
}
|
|
67
78
|
shouldStopAtMaxPhase(def) {
|
|
68
79
|
if (!this.ctx.maxPhase)
|
|
@@ -13,7 +13,20 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
13
13
|
const path_1 = __importDefault(require("path"));
|
|
14
14
|
const child_process_1 = require("child_process");
|
|
15
15
|
const logger_1 = require("../utils/logger");
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Resolve absolute path to templates/codechat/Start-CodeChat.ps1 in the installed package.
|
|
18
|
+
*/
|
|
19
|
+
function resolveStartCodeChatPs1Path() {
|
|
20
|
+
const fromDist = path_1.default.resolve(__dirname, '..', '..', 'templates', 'codechat', 'Start-CodeChat.ps1');
|
|
21
|
+
if (fs_extra_1.default.existsSync(fromDist)) {
|
|
22
|
+
return fromDist;
|
|
23
|
+
}
|
|
24
|
+
const fromCwd = path_1.default.resolve(__dirname, '..', '..', '..', 'templates', 'codechat', 'Start-CodeChat.ps1');
|
|
25
|
+
if (fs_extra_1.default.existsSync(fromCwd)) {
|
|
26
|
+
return fromCwd;
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`未找到 Start-CodeChat.ps1(预期:${fromDist})`);
|
|
29
|
+
}
|
|
17
30
|
const START_MARKER = /^#\s*>>>\s*codechat\s*>>>/;
|
|
18
31
|
const END_MARKER = /^#\s*<<<\s*codechat\s*<<</;
|
|
19
32
|
function assertWin32() {
|
|
@@ -57,8 +70,8 @@ function stripCodechatBlock(content) {
|
|
|
57
70
|
const joined = clean.join('\n').replace(/\n+$/, '');
|
|
58
71
|
return { clean: joined ? `${joined}\n` : '', hadBlock };
|
|
59
72
|
}
|
|
60
|
-
function buildAliasSnippet(
|
|
61
|
-
const escapedPath =
|
|
73
|
+
function buildAliasSnippet(ps1Path) {
|
|
74
|
+
const escapedPath = ps1Path.replace(/'/g, "''");
|
|
62
75
|
return `
|
|
63
76
|
|
|
64
77
|
# >>> codechat >>>
|
|
@@ -69,17 +82,17 @@ function codechat {
|
|
|
69
82
|
[string[]]$ExtraArgs
|
|
70
83
|
)
|
|
71
84
|
if (-not $Path) { $Path = (Get-Location).Path }
|
|
72
|
-
&
|
|
85
|
+
& '${escapedPath}' -Action Start -WorkDir "$Path" @ExtraArgs
|
|
73
86
|
}
|
|
74
87
|
# <<< codechat <<<
|
|
75
88
|
|
|
76
89
|
`;
|
|
77
90
|
}
|
|
78
|
-
function profileHasSvharnessAlias(content,
|
|
91
|
+
function profileHasSvharnessAlias(content, ps1Path) {
|
|
79
92
|
if (!START_MARKER.test(content)) {
|
|
80
93
|
return false;
|
|
81
94
|
}
|
|
82
|
-
const needle = normalizePathForCompare(
|
|
95
|
+
const needle = normalizePathForCompare(ps1Path);
|
|
83
96
|
return normalizePathForCompare(content).includes(needle);
|
|
84
97
|
}
|
|
85
98
|
/**
|
|
@@ -89,11 +102,11 @@ function profileHasSvharnessAlias(content, launchScriptPath) {
|
|
|
89
102
|
async function installCodechatAlias(opts = {}) {
|
|
90
103
|
assertWin32();
|
|
91
104
|
const profilePath = getPowerShellProfilePath();
|
|
92
|
-
const
|
|
105
|
+
const ps1Path = resolveStartCodeChatPs1Path();
|
|
93
106
|
const existing = (await fs_extra_1.default.pathExists(profilePath))
|
|
94
107
|
? await fs_extra_1.default.readFile(profilePath, 'utf8')
|
|
95
108
|
: '';
|
|
96
|
-
if (profileHasSvharnessAlias(existing,
|
|
109
|
+
if (profileHasSvharnessAlias(existing, ps1Path)) {
|
|
97
110
|
if (!opts.silent) {
|
|
98
111
|
logger_1.logger.info(`PowerShell 别名 codechat 已存在:${profilePath}`);
|
|
99
112
|
}
|
|
@@ -104,11 +117,11 @@ async function installCodechatAlias(opts = {}) {
|
|
|
104
117
|
await fs_extra_1.default.writeFile(profilePath, '', 'utf8');
|
|
105
118
|
}
|
|
106
119
|
const { clean, hadBlock } = stripCodechatBlock(existing);
|
|
107
|
-
const snippet = buildAliasSnippet(
|
|
120
|
+
const snippet = buildAliasSnippet(ps1Path);
|
|
108
121
|
await fs_extra_1.default.writeFile(profilePath, `${clean}${snippet}`, 'utf8');
|
|
109
122
|
if (!opts.silent) {
|
|
110
123
|
if (hadBlock) {
|
|
111
|
-
logger_1.logger.success(`已更新 PowerShell 别名 codechat → ${
|
|
124
|
+
logger_1.logger.success(`已更新 PowerShell 别名 codechat → ${ps1Path}`);
|
|
112
125
|
}
|
|
113
126
|
else {
|
|
114
127
|
logger_1.logger.success(`已安装 PowerShell 别名 codechat → ${profilePath}`);
|
|
@@ -144,24 +157,24 @@ async function uninstallCodechatAlias(opts = {}) {
|
|
|
144
157
|
function getCodechatAliasStatus() {
|
|
145
158
|
assertWin32();
|
|
146
159
|
const profilePath = getPowerShellProfilePath();
|
|
147
|
-
let
|
|
160
|
+
let ps1Path = '';
|
|
148
161
|
try {
|
|
149
|
-
|
|
162
|
+
ps1Path = resolveStartCodeChatPs1Path();
|
|
150
163
|
}
|
|
151
164
|
catch {
|
|
152
|
-
|
|
165
|
+
ps1Path = '(未找到)';
|
|
153
166
|
}
|
|
154
167
|
let installed = false;
|
|
155
|
-
if (fs_extra_1.default.existsSync(profilePath) &&
|
|
168
|
+
if (fs_extra_1.default.existsSync(profilePath) && ps1Path !== '(未找到)') {
|
|
156
169
|
try {
|
|
157
170
|
const content = fs_extra_1.default.readFileSync(profilePath, 'utf8');
|
|
158
|
-
installed = profileHasSvharnessAlias(content,
|
|
171
|
+
installed = profileHasSvharnessAlias(content, ps1Path);
|
|
159
172
|
}
|
|
160
173
|
catch {
|
|
161
174
|
installed = false;
|
|
162
175
|
}
|
|
163
176
|
}
|
|
164
|
-
return { profilePath, installed, launchScriptPath };
|
|
177
|
+
return { profilePath, installed, launchScriptPath: ps1Path };
|
|
165
178
|
}
|
|
166
179
|
function printCodechatAliasStatus() {
|
|
167
180
|
const status = getCodechatAliasStatus();
|
|
@@ -3,10 +3,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseReportFrontmatter = parseReportFrontmatter;
|
|
6
7
|
exports.parseReviewReport = parseReviewReport;
|
|
8
|
+
exports.parseGapsFromMarkdown = parseGapsFromMarkdown;
|
|
7
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
10
|
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
9
11
|
const score_aggregator_1 = require("./score-aggregator");
|
|
12
|
+
async function parseReportFrontmatter(reportPath) {
|
|
13
|
+
if (!(await fs_extra_1.default.pathExists(reportPath)))
|
|
14
|
+
return null;
|
|
15
|
+
const content = await fs_extra_1.default.readFile(reportPath, 'utf8');
|
|
16
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
17
|
+
if (!match)
|
|
18
|
+
return null;
|
|
19
|
+
return js_yaml_1.default.load(match[1]);
|
|
20
|
+
}
|
|
10
21
|
async function parseReviewReport(reportPath) {
|
|
11
22
|
if (!(await fs_extra_1.default.pathExists(reportPath)))
|
|
12
23
|
return null;
|
|
@@ -51,6 +62,9 @@ function asRecord(value) {
|
|
|
51
62
|
return typeof value === 'object' && value !== null ? value : {};
|
|
52
63
|
}
|
|
53
64
|
function parseGaps(content) {
|
|
65
|
+
return parseGapsFromMarkdown(content);
|
|
66
|
+
}
|
|
67
|
+
function parseGapsFromMarkdown(content) {
|
|
54
68
|
const gaps = [];
|
|
55
69
|
const lines = content.split(/\r?\n/);
|
|
56
70
|
for (const line of lines) {
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.computeMechanicalScore = computeMechanicalScore;
|
|
4
4
|
exports.computeReviewScore = computeReviewScore;
|
|
5
5
|
exports.computeCompositeScore = computeCompositeScore;
|
|
6
|
+
exports.computeReqPackMechanicalScore = computeReqPackMechanicalScore;
|
|
7
|
+
exports.computeReqPackScore = computeReqPackScore;
|
|
6
8
|
const REVIEW_INTERNAL_WEIGHTS = {
|
|
7
9
|
wiki: 15 / 90,
|
|
8
10
|
requirements: 20 / 90,
|
|
@@ -37,6 +39,25 @@ function computeCompositeScore(review) {
|
|
|
37
39
|
composite: roundScore(clamp(mechanical * 0.30 + reviewScore * 0.70, 0, 10)),
|
|
38
40
|
};
|
|
39
41
|
}
|
|
42
|
+
/** auto_pack_req:硬门禁全通过=10,否则=0 */
|
|
43
|
+
function computeReqPackMechanicalScore(gates, criticalCount) {
|
|
44
|
+
if (gates.doctor_exit !== 0 || gates.verify_exit !== 0 || criticalCount > 0) {
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
return 10;
|
|
48
|
+
}
|
|
49
|
+
/** auto_pack_req 三维度综合分:机械 40% + 对抗 30% + 抽样 30% */
|
|
50
|
+
function computeReqPackScore(gates, adversarialAverage, sampleTraceAverage, criticalCount) {
|
|
51
|
+
const mechanical = computeReqPackMechanicalScore(gates, criticalCount);
|
|
52
|
+
const adversarial = clamp(adversarialAverage, 0, 10);
|
|
53
|
+
const sample_trace = clamp(sampleTraceAverage, 0, 10);
|
|
54
|
+
const composite = roundScore(clamp(mechanical * 0.40 + adversarial * 0.30 + sample_trace * 0.30, 0, 10));
|
|
55
|
+
const gate_pass = gates.doctor_exit === 0 &&
|
|
56
|
+
gates.verify_exit === 0 &&
|
|
57
|
+
criticalCount === 0 &&
|
|
58
|
+
mechanical > 0;
|
|
59
|
+
return { mechanical, adversarial, sample_trace, composite, gate_pass };
|
|
60
|
+
}
|
|
40
61
|
function clamp(value, min, max) {
|
|
41
62
|
if (!Number.isFinite(value))
|
|
42
63
|
return min;
|
package/dist/lib/win-registry.js
CHANGED
|
@@ -86,4 +86,4 @@ function regKeyExists(key) {
|
|
|
86
86
|
}
|
|
87
87
|
exports.SHELL_MENU_KEY_BG = 'HKCU\\Software\\Classes\\Directory\\Background\\shell\\SvharnessLaunchCodeChatAgent';
|
|
88
88
|
exports.SHELL_MENU_KEY_DIR = 'HKCU\\Software\\Classes\\Directory\\shell\\SvharnessLaunchCodeChatAgent';
|
|
89
|
-
exports.SHELL_MENU_LABEL = '
|
|
89
|
+
exports.SHELL_MENU_LABEL = 'Launch CodeChat CLI here';
|
|
@@ -13,6 +13,7 @@ exports.resolveConvertPaths = resolveConvertPaths;
|
|
|
13
13
|
exports.validateConvertArgs = validateConvertArgs;
|
|
14
14
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
15
15
|
const node_path_1 = __importDefault(require("node:path"));
|
|
16
|
+
const convert_1 = require("../constants/convert");
|
|
16
17
|
const harness_name_1 = require("./harness-name");
|
|
17
18
|
const SUPPORTED_ARCHES = [
|
|
18
19
|
'android-compose',
|
|
@@ -161,7 +162,7 @@ function listSupportedAgents() {
|
|
|
161
162
|
}
|
|
162
163
|
const DEFAULT_CONCURRENCY = 3;
|
|
163
164
|
const DEFAULT_MAX_FILE_MB = 50;
|
|
164
|
-
const DEFAULT_TIMEOUT_SEC =
|
|
165
|
+
const DEFAULT_TIMEOUT_SEC = convert_1.DEFAULT_CONVERT_TIMEOUT_SEC;
|
|
165
166
|
const DEFAULT_ENDPOINT = 'http://markitdown.desaysz.site';
|
|
166
167
|
const ENV_ENDPOINT = 'SVHARNESS_MARKITDOWN_ENDPOINT';
|
|
167
168
|
const DEFAULT_CONVERT_TYPE = 'requirements';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svharness",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.13",
|
|
4
4
|
"description": "CLI scaffolder for SDD-Driven Agent-Agnostic Coding Framework (harness)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"svharness": "./bin/cli.js",
|
|
@@ -27,9 +27,10 @@
|
|
|
27
27
|
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
28
28
|
"rebuild": "npm run clean && npm run build",
|
|
29
29
|
"test:requirements": "npm run build && node scripts/test-parse-blocks.js",
|
|
30
|
-
"test:auto": "npm run build && node scripts/test-auto-score.js && node scripts/test-auto-prompt.js",
|
|
30
|
+
"test:auto": "npm run build && node scripts/test-auto-score.js && node scripts/test-auto-prompt.js && node scripts/test-acp-agent-cli-resolver.js && node scripts/test-auto-pack-req-context.js",
|
|
31
31
|
"test:cli-declarations": "npm run build && node scripts/test-cli-input-declarations.js",
|
|
32
32
|
"test:agent-launcher": "npm run build && node scripts/test-agent-launcher.js",
|
|
33
|
+
"test:acp-agent-cli": "npm run build && node scripts/test-acp-agent-cli-resolver.js",
|
|
33
34
|
"prepare": "npm run build",
|
|
34
35
|
"postinstall": "node scripts/postinstall.js",
|
|
35
36
|
"preuninstall": "node scripts/preuninstall.js",
|