svharness 0.15.13 → 0.15.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -36,6 +36,7 @@ async function runAutoPackReq(positionalWorkdir, opts, cmd) {
|
|
|
36
36
|
const workCtx = await (0, auto_pack_req_context_1.resolveAutoPackReqWorkContext)(positionalWorkdir, merged.workDir, merged.requirements);
|
|
37
37
|
const runOpts = {
|
|
38
38
|
...merged,
|
|
39
|
+
harnessName: merged.harnessName ?? auto_pack_req_context_1.PACK_REQ_HARNESS_NAME,
|
|
39
40
|
...(workCtx.requirementsPath ? { requirements: workCtx.requirementsPath } : {}),
|
|
40
41
|
};
|
|
41
42
|
if (workCtx.harnessRoot) {
|
|
@@ -44,10 +45,10 @@ async function runAutoPackReq(positionalWorkdir, opts, cmd) {
|
|
|
44
45
|
}
|
|
45
46
|
else if (workCtx.mode === 'requirements-cwd') {
|
|
46
47
|
logger_1.logger.info(`[auto_pack_req] 当前目录识别为 requirements 输入:${workCtx.requirementsPath}`);
|
|
47
|
-
logger_1.logger.info(`[auto_pack_req]
|
|
48
|
+
logger_1.logger.info(`[auto_pack_req] 将在当前目录创建固定 harness:${node_path_1.default.join(workCtx.workDir, auto_pack_req_context_1.PACK_REQ_HARNESS_DIR)}(等价 --requirements .)`);
|
|
48
49
|
}
|
|
49
50
|
else {
|
|
50
|
-
logger_1.logger.info(
|
|
51
|
+
logger_1.logger.info(`[auto_pack_req] 资料包模式:将创建 ${auto_pack_req_context_1.PACK_REQ_HARNESS_DIR} 并执行 S30+S40`);
|
|
51
52
|
}
|
|
52
53
|
await (0, auto_1.runAuto)(workCtx.workDir, runOpts, cmd);
|
|
53
54
|
}
|
package/dist/commands/auto.js
CHANGED
|
@@ -10,6 +10,7 @@ const node_child_process_1 = require("node:child_process");
|
|
|
10
10
|
const config_1 = require("../config");
|
|
11
11
|
const logger_1 = require("../utils/logger");
|
|
12
12
|
const harness_resolver_1 = require("../lib/harness-resolver");
|
|
13
|
+
const auto_pack_req_context_1 = require("../lib/auto-pack-req-context");
|
|
13
14
|
const auto_orchestrator_1 = require("../lib/auto-orchestrator");
|
|
14
15
|
const dashboard_1 = require("../dashboard");
|
|
15
16
|
const acp_agent_cli_resolver_1 = require("../lib/acp-agent-cli-resolver");
|
|
@@ -70,7 +71,7 @@ async function runAuto(positionalWorkdir, opts, cmd) {
|
|
|
70
71
|
}
|
|
71
72
|
async function resolveAutoContext(positionalWorkdir, opts) {
|
|
72
73
|
const workDir = node_path_1.default.resolve(positionalWorkdir ?? opts.workDir ?? process.cwd());
|
|
73
|
-
const harnessRoot = await (
|
|
74
|
+
const harnessRoot = await resolveHarnessForAuto(workDir, normalizeScope(opts.scope));
|
|
74
75
|
const acpAgentCli = opts.dryRun ? null : (0, acp_agent_cli_resolver_1.ensureAcpAgentCliAvailable)();
|
|
75
76
|
return {
|
|
76
77
|
workDir,
|
|
@@ -122,3 +123,11 @@ function normalizeBaselineExtract(value) {
|
|
|
122
123
|
function normalizeScope(value) {
|
|
123
124
|
return value === 'requirements' ? 'requirements' : 'full';
|
|
124
125
|
}
|
|
126
|
+
async function resolveHarnessForAuto(workDir, scope) {
|
|
127
|
+
if (scope === 'requirements') {
|
|
128
|
+
if (await (0, harness_resolver_1.isHarnessRoot)(workDir))
|
|
129
|
+
return workDir;
|
|
130
|
+
return (0, auto_pack_req_context_1.resolvePackReqHarnessRoot)(workDir);
|
|
131
|
+
}
|
|
132
|
+
return (0, harness_resolver_1.resolveHarnessRoot)(workDir);
|
|
133
|
+
}
|
|
@@ -20,7 +20,12 @@ exports.RAW_SKIP_DIR_NAMES = new Set([
|
|
|
20
20
|
'dist',
|
|
21
21
|
]);
|
|
22
22
|
function shouldSkipRawSubdir(name) {
|
|
23
|
-
|
|
23
|
+
if (exports.RAW_SKIP_DIR_NAMES.has(name))
|
|
24
|
+
return true;
|
|
25
|
+
// auto_pack_req:`--requirements .` 时勿把同级的 `.requirements-harness/` 当作源资料。
|
|
26
|
+
if (name.endsWith('-harness'))
|
|
27
|
+
return true;
|
|
28
|
+
return false;
|
|
24
29
|
}
|
|
25
30
|
/**
|
|
26
31
|
* Recursively list source files for seed intake, skipping harness artifact dirs.
|
|
@@ -12,6 +12,7 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
12
12
|
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
13
13
|
const init_1 = require("../commands/init");
|
|
14
14
|
const harness_name_1 = require("../utils/harness-name");
|
|
15
|
+
const doc_intake_paths_1 = require("../core/doc-intake-paths");
|
|
15
16
|
const logger_1 = require("../utils/logger");
|
|
16
17
|
async function runMaterialsPrepAndBuild(ctx) {
|
|
17
18
|
const detected = await detectInputs(ctx.workDir, ctx.buildOverrides);
|
|
@@ -60,6 +61,8 @@ async function detectInputs(workDir, overrides) {
|
|
|
60
61
|
for (const entry of entries) {
|
|
61
62
|
if (!entry.isDirectory())
|
|
62
63
|
continue;
|
|
64
|
+
if ((0, doc_intake_paths_1.shouldSkipRawSubdir)(entry.name))
|
|
65
|
+
continue;
|
|
63
66
|
const abs = node_path_1.default.join(workDir, entry.name);
|
|
64
67
|
const lower = entry.name.toLowerCase();
|
|
65
68
|
const files = await listFiles(abs, 3);
|
|
@@ -239,10 +242,15 @@ function deriveHarnessName(goal, workDir, log) {
|
|
|
239
242
|
}
|
|
240
243
|
/** Strip non-ASCII, collapse internal hyphens, trim leading/trailing hyphens. */
|
|
241
244
|
function sanitizeToAscii(raw) {
|
|
242
|
-
|
|
245
|
+
const ascii = raw
|
|
243
246
|
.toLowerCase()
|
|
244
247
|
.replace(/[^a-z0-9]+/g, '-')
|
|
245
248
|
.replace(/^-+|-+$/g, '');
|
|
249
|
+
// Goal 模板常含「构建 harness」,与 workDir 叠在一起会得到 `xxx-harness` 短名。
|
|
250
|
+
const core = (0, harness_name_1.stripHarnessSuffixFromCore)(ascii);
|
|
251
|
+
if (!core || core === 'harness')
|
|
252
|
+
return '';
|
|
253
|
+
return core;
|
|
246
254
|
}
|
|
247
255
|
function detectArchFromDetected(detected) {
|
|
248
256
|
const baseline = detected.baseline?.path;
|
|
@@ -3,12 +3,17 @@ 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.PACK_REQ_HARNESS_DIR = exports.PACK_REQ_HARNESS_NAME = void 0;
|
|
6
7
|
exports.looksLikeMaterialsPackRoot = looksLikeMaterialsPackRoot;
|
|
7
8
|
exports.looksLikeRequirementsFolder = looksLikeRequirementsFolder;
|
|
9
|
+
exports.resolvePackReqHarnessRoot = resolvePackReqHarnessRoot;
|
|
8
10
|
exports.resolveAutoPackReqWorkContext = resolveAutoPackReqWorkContext;
|
|
9
11
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
12
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
13
|
const harness_resolver_1 = require("./harness-resolver");
|
|
14
|
+
/** auto_pack_req 固定短名 → 目录 `.requirements-harness/` */
|
|
15
|
+
exports.PACK_REQ_HARNESS_NAME = '.requirements';
|
|
16
|
+
exports.PACK_REQ_HARNESS_DIR = '.requirements-harness';
|
|
12
17
|
const DOC_FILE_RE = /\.(md|docx|doc|pdf|xlsx|xls|pptx|ppt|txt|csv)$/i;
|
|
13
18
|
const MATERIALS_PACK_SUBDIR_RE = /^(requirements?|baseline|references?|extra[-_]?skills?|需求|接口|协议|skill)/i;
|
|
14
19
|
/** 当前目录是否像资料包根(含 requirements/、baseline/ 等子目录) */
|
|
@@ -46,15 +51,33 @@ async function looksLikeRequirementsFolder(dir) {
|
|
|
46
51
|
}
|
|
47
52
|
return false;
|
|
48
53
|
}
|
|
54
|
+
/** 仅识别 workDir 下固定的 `.requirements-harness/`,不扫描其它 `*-harness/`。 */
|
|
55
|
+
async function resolvePackReqHarnessRoot(workDir) {
|
|
56
|
+
const candidate = node_path_1.default.join(node_path_1.default.resolve(workDir), exports.PACK_REQ_HARNESS_DIR);
|
|
57
|
+
return (await (0, harness_resolver_1.isHarnessRoot)(candidate)) ? candidate : null;
|
|
58
|
+
}
|
|
49
59
|
/**
|
|
50
60
|
* 解析 auto_pack_req 工作上下文。
|
|
51
|
-
* 无显式 workdir 时:若当前目录本身是 requirements
|
|
61
|
+
* 无显式 workdir 时:若当前目录本身是 requirements 资料夹,则 workDir 保持为当前目录,
|
|
62
|
+
* requirements 输入等价于 `--requirements .`,harness 固定为 `./.requirements-harness/`。
|
|
52
63
|
*/
|
|
53
64
|
async function resolveAutoPackReqWorkContext(positionalWorkdir, configWorkDir, requirementsOverride) {
|
|
54
65
|
const explicit = positionalWorkdir ?? configWorkDir;
|
|
55
66
|
if (explicit) {
|
|
56
67
|
const workDir = node_path_1.default.resolve(explicit);
|
|
57
|
-
|
|
68
|
+
if (await (0, harness_resolver_1.isHarnessRoot)(workDir)) {
|
|
69
|
+
return {
|
|
70
|
+
workDir,
|
|
71
|
+
harnessRoot: workDir,
|
|
72
|
+
requirementsPath: requirementsOverride
|
|
73
|
+
? node_path_1.default.isAbsolute(requirementsOverride)
|
|
74
|
+
? requirementsOverride
|
|
75
|
+
: node_path_1.default.resolve(workDir, requirementsOverride)
|
|
76
|
+
: undefined,
|
|
77
|
+
mode: 'harness-rerun',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const harnessRoot = await resolvePackReqHarnessRoot(workDir);
|
|
58
81
|
return {
|
|
59
82
|
workDir,
|
|
60
83
|
harnessRoot,
|
|
@@ -67,22 +90,26 @@ async function resolveAutoPackReqWorkContext(positionalWorkdir, configWorkDir, r
|
|
|
67
90
|
};
|
|
68
91
|
}
|
|
69
92
|
const cwd = process.cwd();
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return { workDir: cwd, harnessRoot: harnessFromCwd, mode: 'harness-rerun' };
|
|
93
|
+
if (await (0, harness_resolver_1.isHarnessRoot)(cwd)) {
|
|
94
|
+
return { workDir: cwd, harnessRoot: cwd, mode: 'harness-rerun' };
|
|
73
95
|
}
|
|
74
96
|
if (await looksLikeMaterialsPackRoot(cwd)) {
|
|
75
|
-
|
|
97
|
+
const harnessRoot = await resolvePackReqHarnessRoot(cwd);
|
|
98
|
+
return { workDir: cwd, harnessRoot, mode: harnessRoot ? 'harness-rerun' : 'materials-pack' };
|
|
76
99
|
}
|
|
77
100
|
if (await looksLikeRequirementsFolder(cwd)) {
|
|
78
|
-
const
|
|
79
|
-
const harnessFromParent = await (0, harness_resolver_1.resolveHarnessRoot)(parent);
|
|
101
|
+
const harnessRoot = await resolvePackReqHarnessRoot(cwd);
|
|
80
102
|
return {
|
|
81
|
-
workDir:
|
|
82
|
-
harnessRoot
|
|
103
|
+
workDir: cwd,
|
|
104
|
+
harnessRoot,
|
|
83
105
|
requirementsPath: node_path_1.default.resolve(cwd),
|
|
84
|
-
mode:
|
|
106
|
+
mode: harnessRoot ? 'harness-rerun' : 'requirements-cwd',
|
|
85
107
|
};
|
|
86
108
|
}
|
|
87
|
-
|
|
109
|
+
const harnessRoot = await resolvePackReqHarnessRoot(cwd);
|
|
110
|
+
return {
|
|
111
|
+
workDir: cwd,
|
|
112
|
+
harnessRoot,
|
|
113
|
+
mode: harnessRoot ? 'harness-rerun' : 'materials-pack',
|
|
114
|
+
};
|
|
88
115
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.normalizeHarnessName = normalizeHarnessName;
|
|
4
4
|
exports.harnessNameCore = harnessNameCore;
|
|
5
|
+
exports.stripHarnessSuffixFromCore = stripHarnessSuffixFromCore;
|
|
5
6
|
exports.validateHarnessNameInput = validateHarnessNameInput;
|
|
6
7
|
exports.harnessDirNameFromName = harnessDirNameFromName;
|
|
7
8
|
/**
|
|
@@ -22,6 +23,17 @@ function harnessNameCore(raw) {
|
|
|
22
23
|
const trimmed = raw.trim();
|
|
23
24
|
return trimmed.startsWith('.') ? trimmed.slice(1) : trimmed;
|
|
24
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Strip redundant `-harness` suffix(es) from an inferred name core.
|
|
28
|
+
* e.g. `requirements-harness` → `requirements`, `foo-harness-harness` → `foo`.
|
|
29
|
+
*/
|
|
30
|
+
function stripHarnessSuffixFromCore(core) {
|
|
31
|
+
let result = core;
|
|
32
|
+
while (result.endsWith('-harness')) {
|
|
33
|
+
result = result.slice(0, -'-harness'.length);
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
25
37
|
function validateHarnessNameInput(raw) {
|
|
26
38
|
if (!raw?.trim()) {
|
|
27
39
|
return { ok: false, message: '--harness-name 为必填参数' };
|
|
@@ -37,5 +49,11 @@ function validateHarnessNameInput(raw) {
|
|
|
37
49
|
return { ok: true, normalized: normalizeHarnessName(raw) };
|
|
38
50
|
}
|
|
39
51
|
function harnessDirNameFromName(harnessName) {
|
|
40
|
-
|
|
52
|
+
const normalized = normalizeHarnessName(harnessName);
|
|
53
|
+
const core = harnessNameCore(normalized);
|
|
54
|
+
// Avoid `.foo-harness-harness` when the short name already ends with `-harness`.
|
|
55
|
+
if (core.endsWith('-harness')) {
|
|
56
|
+
return normalized;
|
|
57
|
+
}
|
|
58
|
+
return `${normalized}-harness`;
|
|
41
59
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svharness",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.14",
|
|
4
4
|
"description": "CLI scaffolder for SDD-Driven Agent-Agnostic Coding Framework (harness)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"svharness": "./bin/cli.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
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 && node scripts/test-acp-agent-cli-resolver.js && node scripts/test-auto-pack-req-context.js",
|
|
30
|
+
"test:auto": "npm run build && node scripts/test-harness-name.js && node scripts/test-doc-intake-paths.js && 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
33
|
"test:acp-agent-cli": "npm run build && node scripts/test-acp-agent-cli-resolver.js",
|