@hongmaple0820/scale-engine 0.17.0 → 0.18.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.
- package/dist/api/cli.js +214 -7
- package/dist/api/cli.js.map +1 -1
- package/dist/api/doctor.d.ts +1 -0
- package/dist/api/doctor.js +45 -0
- package/dist/api/doctor.js.map +1 -1
- package/dist/api/quickstart.js +5 -2
- package/dist/api/quickstart.js.map +1 -1
- package/dist/core/logger.js +1 -1
- package/dist/output/HTMLArtifactLayer.d.ts +97 -0
- package/dist/output/HTMLArtifactLayer.js +576 -0
- package/dist/output/HTMLArtifactLayer.js.map +1 -0
- package/dist/output/index.d.ts +2 -0
- package/dist/output/index.js +1 -0
- package/dist/output/index.js.map +1 -1
- package/dist/skills/routing/SkillGate.js +26 -2
- package/dist/skills/routing/SkillGate.js.map +1 -1
- package/dist/skills/routing/SkillPolicy.js +2 -2
- package/dist/skills/routing/SkillPolicy.js.map +1 -1
- package/dist/tools/ToolCapabilityRegistry.d.ts +1 -1
- package/dist/tools/ToolCapabilityRegistry.js +4 -4
- package/dist/tools/ToolCapabilityRegistry.js.map +1 -1
- package/dist/tools/ToolOrchestrator.js +5 -1
- package/dist/tools/ToolOrchestrator.js.map +1 -1
- package/dist/workflow/GovernanceTemplatePacks.d.ts +1 -1
- package/dist/workflow/GovernanceTemplatePacks.js +77 -19
- package/dist/workflow/GovernanceTemplatePacks.js.map +1 -1
- package/dist/workflow/GovernanceTemplates.js +36 -12
- package/dist/workflow/GovernanceTemplates.js.map +1 -1
- package/dist/workflow/ResourceGovernance.js +2 -1
- package/dist/workflow/ResourceGovernance.js.map +1 -1
- package/package.json +2 -2
package/dist/api/cli.js
CHANGED
|
@@ -30,7 +30,7 @@ import { EvidenceStore } from '../workflow/EvidenceStore.js';
|
|
|
30
30
|
import { OutOfScopeStore } from '../workflow/OutOfScopeStore.js';
|
|
31
31
|
import { ReviewStore } from '../workflow/ReviewStore.js';
|
|
32
32
|
import { WorkflowEngine } from '../workflow/WorkflowEngine.js';
|
|
33
|
-
import { resolveVerificationTargets } from '../workflow/VerificationProfile.js';
|
|
33
|
+
import { resolveVerificationTargets, } from '../workflow/VerificationProfile.js';
|
|
34
34
|
import { writeGovernanceTemplates } from '../workflow/GovernanceTemplates.js';
|
|
35
35
|
import { computeGovernanceDrift } from '../workflow/GovernanceLock.js';
|
|
36
36
|
import { baselineEngineeringStandards, doctorEngineeringStandards, scanEngineeringStandards, settleEngineeringStandards, } from '../workflow/EngineeringStandards.js';
|
|
@@ -47,11 +47,13 @@ import { evaluateToolEvidenceGate } from '../tools/ToolEvidenceGate.js';
|
|
|
47
47
|
import { ToolEvidenceStore } from '../tools/ToolEvidenceStore.js';
|
|
48
48
|
import { ToolOrchestrator } from '../tools/ToolOrchestrator.js';
|
|
49
49
|
import { loadToolPolicy, toolPolicyTemplate } from '../tools/ToolPolicy.js';
|
|
50
|
+
import { doctorHtmlArtifacts, renderHtmlArtifact, resolveHtmlArtifactForOpen, settleHtmlArtifacts, } from '../output/HTMLArtifactLayer.js';
|
|
50
51
|
import { cleanupWorkspaceLifecycle, inspectWorkspaceLifecycle, } from '../workflow/WorkspaceLifecycle.js';
|
|
51
52
|
import { resolveWorkspaceTopology, workspaceTopologyPath, workspaceTopologyTemplate, } from '../workflow/WorkspaceTopology.js';
|
|
52
53
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
53
54
|
import { join, resolve } from 'node:path';
|
|
54
55
|
import { execFileSync } from 'node:child_process';
|
|
56
|
+
import { pathToFileURL } from 'node:url';
|
|
55
57
|
import { SCALE_ENGINE_VERSION } from '../version.js';
|
|
56
58
|
// ============================================================================
|
|
57
59
|
// Engine bootstrap (单例 + lazy init)
|
|
@@ -96,6 +98,26 @@ function gatesForPreflightProfile(profile) {
|
|
|
96
98
|
return ['G3', 'G0', 'G4', 'G5'];
|
|
97
99
|
return ['G3', 'G0', 'G4', 'G5', 'G6', 'G7'];
|
|
98
100
|
}
|
|
101
|
+
function shouldSkipPreflightCommandTargets(resolved, args) {
|
|
102
|
+
if (!resolved.matrix)
|
|
103
|
+
return false;
|
|
104
|
+
const requestedService = String(args.service ?? '').trim();
|
|
105
|
+
if (requestedService && requestedService !== 'all')
|
|
106
|
+
return false;
|
|
107
|
+
const hasCommandOverrides = [
|
|
108
|
+
args['build-cmd'],
|
|
109
|
+
args['lint-cmd'],
|
|
110
|
+
args['test-cmd'],
|
|
111
|
+
args['coverage-cmd'],
|
|
112
|
+
].some(value => typeof value === 'string' && value.trim().length > 0);
|
|
113
|
+
if (hasCommandOverrides)
|
|
114
|
+
return false;
|
|
115
|
+
const profile = resolved.matrix.profiles?.[resolved.profileName];
|
|
116
|
+
const hasProfileCommands = Object.values(profile?.commands ?? {})
|
|
117
|
+
.some(value => typeof value === 'string' && value.trim().length > 0);
|
|
118
|
+
const hasServices = (resolved.matrix.services ?? []).length > 0;
|
|
119
|
+
return !hasServices && !hasProfileCommands;
|
|
120
|
+
}
|
|
99
121
|
function evaluateEngineeringStandardsGate(options) {
|
|
100
122
|
const mode = normalizeEngineeringStandardsGateMode(options.policy.engineeringStandardsGate);
|
|
101
123
|
if (mode === 'off') {
|
|
@@ -1378,6 +1400,10 @@ const preflight = defineCommand({
|
|
|
1378
1400
|
profile: args.profile,
|
|
1379
1401
|
service: args.service,
|
|
1380
1402
|
});
|
|
1403
|
+
const commandTargetsSkipped = shouldSkipPreflightCommandTargets(resolved, args);
|
|
1404
|
+
if (commandTargetsSkipped) {
|
|
1405
|
+
resolved.warnings.push('No verification services or profile commands configured; command gates skipped for this governance-only project.');
|
|
1406
|
+
}
|
|
1381
1407
|
const engineeringStandards = evaluateEngineeringStandardsGate({
|
|
1382
1408
|
policy: resolved.policy,
|
|
1383
1409
|
});
|
|
@@ -1397,7 +1423,7 @@ const preflight = defineCommand({
|
|
|
1397
1423
|
console.log(' Engineering standards: skipped');
|
|
1398
1424
|
}
|
|
1399
1425
|
}
|
|
1400
|
-
for (const target of resolved.targets) {
|
|
1426
|
+
for (const target of commandTargetsSkipped ? [] : resolved.targets) {
|
|
1401
1427
|
if (!args.json) {
|
|
1402
1428
|
const label = target.service ? `${target.service.name} (${target.service.path})` : 'root';
|
|
1403
1429
|
console.log(`\n Target: ${label}`);
|
|
@@ -1427,8 +1453,7 @@ const preflight = defineCommand({
|
|
|
1427
1453
|
}
|
|
1428
1454
|
}
|
|
1429
1455
|
}
|
|
1430
|
-
const passed = targetResults.length
|
|
1431
|
-
targetResults.every(target => target.passed) &&
|
|
1456
|
+
const passed = (targetResults.length === 0 || targetResults.every(target => target.passed)) &&
|
|
1432
1457
|
!engineeringStandards.blocked;
|
|
1433
1458
|
const result = {
|
|
1434
1459
|
phase: 'PREFLIGHT',
|
|
@@ -1439,6 +1464,7 @@ const preflight = defineCommand({
|
|
|
1439
1464
|
policy: resolved.policy,
|
|
1440
1465
|
engineeringStandards,
|
|
1441
1466
|
targets: targetResults,
|
|
1467
|
+
commandTargetsSkipped,
|
|
1442
1468
|
passed,
|
|
1443
1469
|
};
|
|
1444
1470
|
if (args.json) {
|
|
@@ -1689,7 +1715,7 @@ const init = defineCommand({
|
|
|
1689
1715
|
const detection = qsResult.success ? undefined : detectPlatform(args.dir);
|
|
1690
1716
|
console.log(JSON.stringify({
|
|
1691
1717
|
ok: qsResult.success,
|
|
1692
|
-
mode: 'quick',
|
|
1718
|
+
mode: qsResult.success && !qsResult.platform ? 'governance-only' : 'quick',
|
|
1693
1719
|
platform: qsResult.platform,
|
|
1694
1720
|
created: qsResult.created,
|
|
1695
1721
|
skipped: qsResult.skipped,
|
|
@@ -1701,8 +1727,11 @@ const init = defineCommand({
|
|
|
1701
1727
|
}, null, 2));
|
|
1702
1728
|
return;
|
|
1703
1729
|
}
|
|
1704
|
-
if (qsResult.success
|
|
1705
|
-
|
|
1730
|
+
if (qsResult.success) {
|
|
1731
|
+
if (!qsResult.platform)
|
|
1732
|
+
console.log(`\nSCALE governance templates initialized`);
|
|
1733
|
+
else
|
|
1734
|
+
console.log(`\n✅ SCALE Engine Quick Start completed for ${qsResult.platform}`);
|
|
1706
1735
|
console.log(`\n📁 Created (${qsResult.created.length}):`);
|
|
1707
1736
|
for (const f of qsResult.created)
|
|
1708
1737
|
console.log(` + ${f}`);
|
|
@@ -2056,6 +2085,182 @@ const standards = defineCommand({
|
|
|
2056
2085
|
subCommands: { scan: standardsScan, doctor: standardsDoctor, settle: standardsSettle, baseline: standardsBaseline },
|
|
2057
2086
|
});
|
|
2058
2087
|
// ============================================================================
|
|
2088
|
+
// artifact command - Derived HTML artifacts for human review
|
|
2089
|
+
// ============================================================================
|
|
2090
|
+
const artifactRender = defineCommand({
|
|
2091
|
+
meta: { name: 'render', description: 'Render a task Markdown source set into a governed HTML artifact' },
|
|
2092
|
+
args: {
|
|
2093
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2094
|
+
'task-id': { type: 'string', description: 'Task id under docs/worklog/tasks' },
|
|
2095
|
+
'artifact-dir': { type: 'string', description: 'Task artifact directory override' },
|
|
2096
|
+
type: { type: 'string', default: 'release-report', description: 'HTML artifact type' },
|
|
2097
|
+
source: { type: 'string', description: 'Comma or newline separated source Markdown files relative to the task directory' },
|
|
2098
|
+
theme: { type: 'string', default: 'auto', description: 'Theme mode: dark/light/auto' },
|
|
2099
|
+
lang: { type: 'string', default: 'zh', description: 'HTML language: zh/en' },
|
|
2100
|
+
title: { type: 'string', description: 'HTML document title override' },
|
|
2101
|
+
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
2102
|
+
},
|
|
2103
|
+
run({ args }) {
|
|
2104
|
+
const result = renderHtmlArtifact({
|
|
2105
|
+
projectDir: args.dir,
|
|
2106
|
+
taskId: args['task-id'],
|
|
2107
|
+
artifactDir: args['artifact-dir'],
|
|
2108
|
+
type: String(args.type ?? 'release-report'),
|
|
2109
|
+
sourcePaths: splitChangedFiles(typeof args.source === 'string' ? args.source : undefined),
|
|
2110
|
+
theme: normalizeThemeArg(args.theme),
|
|
2111
|
+
lang: normalizeLangArg(args.lang),
|
|
2112
|
+
title: typeof args.title === 'string' ? args.title : undefined,
|
|
2113
|
+
});
|
|
2114
|
+
if (args.json) {
|
|
2115
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
console.log('SCALE HTML Artifact Render');
|
|
2119
|
+
console.log(` Type: ${result.type}`);
|
|
2120
|
+
console.log(` HTML: ${result.outputPath}`);
|
|
2121
|
+
console.log(` Index: ${result.indexPath}`);
|
|
2122
|
+
console.log(` Manifest: ${result.manifestPath}`);
|
|
2123
|
+
if (result.missingSources.length > 0) {
|
|
2124
|
+
console.log(` Missing sources: ${result.missingSources.join(', ')}`);
|
|
2125
|
+
}
|
|
2126
|
+
},
|
|
2127
|
+
});
|
|
2128
|
+
const artifactDoctor = defineCommand({
|
|
2129
|
+
meta: { name: 'doctor', description: 'Check HTML artifacts for traceability, stale sources, remote assets, and secret-like content' },
|
|
2130
|
+
args: {
|
|
2131
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2132
|
+
'task-id': { type: 'string', description: 'Task id under docs/worklog/tasks' },
|
|
2133
|
+
'artifact-dir': { type: 'string', description: 'Task artifact directory override' },
|
|
2134
|
+
type: { type: 'string', description: 'Optional HTML artifact type to check' },
|
|
2135
|
+
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
2136
|
+
},
|
|
2137
|
+
run({ args }) {
|
|
2138
|
+
const report = doctorHtmlArtifacts({
|
|
2139
|
+
projectDir: args.dir,
|
|
2140
|
+
taskId: args['task-id'],
|
|
2141
|
+
artifactDir: args['artifact-dir'],
|
|
2142
|
+
type: typeof args.type === 'string' ? args.type : undefined,
|
|
2143
|
+
});
|
|
2144
|
+
if (args.json) {
|
|
2145
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2146
|
+
if (!report.ok)
|
|
2147
|
+
process.exitCode = 1;
|
|
2148
|
+
return;
|
|
2149
|
+
}
|
|
2150
|
+
console.log(`SCALE HTML Artifact Doctor: ${report.ok ? 'OK' : 'FAILED'}`);
|
|
2151
|
+
console.log(` Manifest: ${report.manifestPath}`);
|
|
2152
|
+
console.log(` Artifacts: ${report.artifacts.length}`);
|
|
2153
|
+
if (report.findings.length === 0) {
|
|
2154
|
+
console.log(' No HTML artifact findings.');
|
|
2155
|
+
}
|
|
2156
|
+
else {
|
|
2157
|
+
for (const finding of report.findings) {
|
|
2158
|
+
const path = finding.path ? ` ${finding.path}` : '';
|
|
2159
|
+
console.log(` [${finding.severity.toUpperCase()}] ${finding.code}${path}: ${finding.message}`);
|
|
2160
|
+
if (finding.fix)
|
|
2161
|
+
console.log(` fix: ${finding.fix}`);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
if (!report.ok)
|
|
2165
|
+
process.exitCode = 1;
|
|
2166
|
+
},
|
|
2167
|
+
});
|
|
2168
|
+
const artifactSettle = defineCommand({
|
|
2169
|
+
meta: { name: 'settle', description: 'Record HTML artifact settlement evidence for a task' },
|
|
2170
|
+
args: {
|
|
2171
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2172
|
+
'task-id': { type: 'string', description: 'Task id under docs/worklog/tasks' },
|
|
2173
|
+
'artifact-dir': { type: 'string', description: 'Task artifact directory override' },
|
|
2174
|
+
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
2175
|
+
},
|
|
2176
|
+
run({ args }) {
|
|
2177
|
+
const report = settleHtmlArtifacts({
|
|
2178
|
+
projectDir: args.dir,
|
|
2179
|
+
taskId: args['task-id'],
|
|
2180
|
+
artifactDir: args['artifact-dir'],
|
|
2181
|
+
});
|
|
2182
|
+
if (args.json) {
|
|
2183
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2184
|
+
if (!report.ok)
|
|
2185
|
+
process.exitCode = 1;
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
console.log(`SCALE HTML Artifact Settlement: ${report.ok ? 'OK' : 'FAILED'}`);
|
|
2189
|
+
console.log(` HTML impact: ${report.htmlImpactPath}`);
|
|
2190
|
+
for (const finding of report.doctor.findings) {
|
|
2191
|
+
const path = finding.path ? ` ${finding.path}` : '';
|
|
2192
|
+
console.log(` [${finding.severity.toUpperCase()}] ${finding.code}${path}: ${finding.message}`);
|
|
2193
|
+
}
|
|
2194
|
+
if (!report.ok)
|
|
2195
|
+
process.exitCode = 1;
|
|
2196
|
+
},
|
|
2197
|
+
});
|
|
2198
|
+
const artifactOpen = defineCommand({
|
|
2199
|
+
meta: { name: 'open', description: 'Open or print the local file URL for a rendered HTML artifact' },
|
|
2200
|
+
args: {
|
|
2201
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2202
|
+
'task-id': { type: 'string', description: 'Task id under docs/worklog/tasks' },
|
|
2203
|
+
'artifact-dir': { type: 'string', description: 'Task artifact directory override' },
|
|
2204
|
+
type: { type: 'string', description: 'Optional HTML artifact type to open' },
|
|
2205
|
+
'print-only': { type: 'boolean', default: false, description: 'Only print the file URL without launching a browser' },
|
|
2206
|
+
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
2207
|
+
},
|
|
2208
|
+
run({ args }) {
|
|
2209
|
+
const path = resolveHtmlArtifactForOpen({
|
|
2210
|
+
projectDir: args.dir,
|
|
2211
|
+
taskId: args['task-id'],
|
|
2212
|
+
artifactDir: args['artifact-dir'],
|
|
2213
|
+
type: typeof args.type === 'string' ? args.type : undefined,
|
|
2214
|
+
});
|
|
2215
|
+
const url = pathToFileURL(path).toString();
|
|
2216
|
+
const exists = existsSync(path);
|
|
2217
|
+
if (!args['print-only'] && exists)
|
|
2218
|
+
launchLocalFile(path);
|
|
2219
|
+
const output = { ok: exists, path, url, launched: Boolean(!args['print-only'] && exists) };
|
|
2220
|
+
if (args.json) {
|
|
2221
|
+
console.log(JSON.stringify(output, null, 2));
|
|
2222
|
+
if (!exists)
|
|
2223
|
+
process.exitCode = 1;
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
if (!exists) {
|
|
2227
|
+
console.log(`HTML artifact not found: ${path}`);
|
|
2228
|
+
process.exitCode = 1;
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
console.log(url);
|
|
2232
|
+
},
|
|
2233
|
+
});
|
|
2234
|
+
const artifact = defineCommand({
|
|
2235
|
+
meta: { name: 'artifact', description: 'Derived HTML artifact rendering and safety checks' },
|
|
2236
|
+
subCommands: { render: artifactRender, doctor: artifactDoctor, settle: artifactSettle, open: artifactOpen },
|
|
2237
|
+
});
|
|
2238
|
+
function normalizeThemeArg(value) {
|
|
2239
|
+
const normalized = String(value ?? 'auto').trim().toLowerCase();
|
|
2240
|
+
if (normalized === 'dark' || normalized === 'light' || normalized === 'auto')
|
|
2241
|
+
return normalized;
|
|
2242
|
+
return 'auto';
|
|
2243
|
+
}
|
|
2244
|
+
function normalizeLangArg(value) {
|
|
2245
|
+
return String(value ?? 'zh').trim().toLowerCase() === 'en' ? 'en' : 'zh';
|
|
2246
|
+
}
|
|
2247
|
+
function launchLocalFile(path) {
|
|
2248
|
+
try {
|
|
2249
|
+
if (process.platform === 'win32') {
|
|
2250
|
+
execFileSync('cmd', ['/c', 'start', '', path], { stdio: 'ignore' });
|
|
2251
|
+
}
|
|
2252
|
+
else if (process.platform === 'darwin') {
|
|
2253
|
+
execFileSync('open', [path], { stdio: 'ignore' });
|
|
2254
|
+
}
|
|
2255
|
+
else {
|
|
2256
|
+
execFileSync('xdg-open', [path], { stdio: 'ignore' });
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
catch {
|
|
2260
|
+
// Opening is convenience-only; artifact doctor/render remains the source of truth.
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
// ============================================================================
|
|
2059
2264
|
// evolve command
|
|
2060
2265
|
// ============================================================================
|
|
2061
2266
|
const evolve = defineCommand({
|
|
@@ -2453,6 +2658,7 @@ const skillCheckCommand = defineCommand({
|
|
|
2453
2658
|
artifactsDir: args.dir ?? state?.artifactsDir,
|
|
2454
2659
|
level,
|
|
2455
2660
|
requiredArtifacts: state?.requiredSkillArtifacts,
|
|
2661
|
+
requiredSkills: state?.requiredSkills,
|
|
2456
2662
|
mode: state?.skillRoutingMode ?? policy.policy.mode,
|
|
2457
2663
|
enforceLevels: policy.policy.enforceLevels,
|
|
2458
2664
|
});
|
|
@@ -3005,6 +3211,7 @@ const main = defineCommand({
|
|
|
3005
3211
|
stats,
|
|
3006
3212
|
preflight,
|
|
3007
3213
|
governance,
|
|
3214
|
+
artifact,
|
|
3008
3215
|
assets,
|
|
3009
3216
|
standards,
|
|
3010
3217
|
metrics,
|