@hongmaple0820/scale-engine 0.15.1 → 0.16.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/agents/LeadershipPresets.d.ts +16 -0
- package/dist/agents/LeadershipPresets.js +152 -0
- package/dist/agents/LeadershipPresets.js.map +1 -0
- package/dist/api/cli.js +494 -6
- package/dist/api/cli.js.map +1 -1
- package/dist/artifact/types.d.ts +4 -0
- package/dist/artifact/types.js.map +1 -1
- package/dist/cli/phaseCommands.d.ts +14 -0
- package/dist/cli/phaseCommands.js +153 -2
- package/dist/cli/phaseCommands.js.map +1 -1
- package/dist/cli/vibeCommands.d.ts +20 -0
- package/dist/cli/vibeCommands.js +150 -173
- package/dist/cli/vibeCommands.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/prompts/VibeTemplateGallery.d.ts +25 -0
- package/dist/prompts/VibeTemplateGallery.js +295 -0
- package/dist/prompts/VibeTemplateGallery.js.map +1 -0
- package/dist/skills/SkillRepository.d.ts +63 -0
- package/dist/skills/SkillRepository.js +365 -0
- package/dist/skills/SkillRepository.js.map +1 -0
- package/dist/tools/ToolCapabilityRegistry.d.ts +46 -0
- package/dist/tools/ToolCapabilityRegistry.js +223 -0
- package/dist/tools/ToolCapabilityRegistry.js.map +1 -0
- package/dist/tools/ToolEvidenceGate.d.ts +39 -0
- package/dist/tools/ToolEvidenceGate.js +117 -0
- package/dist/tools/ToolEvidenceGate.js.map +1 -0
- package/dist/tools/ToolEvidenceStore.d.ts +58 -0
- package/dist/tools/ToolEvidenceStore.js +129 -0
- package/dist/tools/ToolEvidenceStore.js.map +1 -0
- package/dist/tools/ToolOrchestrator.d.ts +67 -0
- package/dist/tools/ToolOrchestrator.js +193 -0
- package/dist/tools/ToolOrchestrator.js.map +1 -0
- package/dist/tools/ToolPolicy.d.ts +33 -0
- package/dist/tools/ToolPolicy.js +157 -0
- package/dist/tools/ToolPolicy.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/workflow/EngineeringStandards.d.ts +69 -0
- package/dist/workflow/EngineeringStandards.js +348 -6
- package/dist/workflow/EngineeringStandards.js.map +1 -1
- package/dist/workflow/GovernanceTemplatePacks.js +11 -9
- package/dist/workflow/GovernanceTemplatePacks.js.map +1 -1
- package/dist/workflow/GovernanceTemplates.js +15 -4
- package/dist/workflow/GovernanceTemplates.js.map +1 -1
- package/package.json +2 -2
package/dist/api/cli.js
CHANGED
|
@@ -23,6 +23,8 @@ import { Doctor } from './doctor.js';
|
|
|
23
23
|
import { quickStart, detectPlatform } from './quickstart.js';
|
|
24
24
|
import { SkillDiscovery } from '../skills/SkillDiscovery.js';
|
|
25
25
|
import { inspectRequiredWorkflowSkills, inspectWorkflowSkills } from '../skills/SkillDoctor.js';
|
|
26
|
+
import { evaluateSkillInstallSafety, listSkillRepositoryEntries, recommendSkillWorkflow, renderSkillRepositoryMarkdown, } from '../skills/SkillRepository.js';
|
|
27
|
+
import { listLeadershipPresets, renderLeadershipPresetsMarkdown } from '../agents/LeadershipPresets.js';
|
|
26
28
|
import { listWorkflowPresets, getPresetsByScenario } from '../workflows/presets.js';
|
|
27
29
|
import { EvidenceStore } from '../workflow/EvidenceStore.js';
|
|
28
30
|
import { OutOfScopeStore } from '../workflow/OutOfScopeStore.js';
|
|
@@ -31,15 +33,21 @@ import { WorkflowEngine } from '../workflow/WorkflowEngine.js';
|
|
|
31
33
|
import { resolveVerificationTargets } from '../workflow/VerificationProfile.js';
|
|
32
34
|
import { writeGovernanceTemplates } from '../workflow/GovernanceTemplates.js';
|
|
33
35
|
import { computeGovernanceDrift } from '../workflow/GovernanceLock.js';
|
|
34
|
-
import { doctorEngineeringStandards, scanEngineeringStandards, settleEngineeringStandards, } from '../workflow/EngineeringStandards.js';
|
|
36
|
+
import { baselineEngineeringStandards, doctorEngineeringStandards, scanEngineeringStandards, settleEngineeringStandards, } from '../workflow/EngineeringStandards.js';
|
|
35
37
|
import { doctorResourceAssets, scanResourceAssets, settleResourceAssets } from '../workflow/ResourceGovernance.js';
|
|
36
38
|
import { TaskMetricsStore } from '../workflow/TaskMetricsStore.js';
|
|
37
39
|
import { checkTaskArtifactCompleteness } from '../workflow/TaskArtifactScaffolder.js';
|
|
38
40
|
import { WorkflowArtifactWriter } from '../workflow/WorkflowArtifactWriter.js';
|
|
41
|
+
import { inspectToolCapabilities } from '../tools/ToolCapabilityRegistry.js';
|
|
42
|
+
import { evaluateToolEvidenceGate } from '../tools/ToolEvidenceGate.js';
|
|
43
|
+
import { ToolEvidenceStore } from '../tools/ToolEvidenceStore.js';
|
|
44
|
+
import { ToolOrchestrator } from '../tools/ToolOrchestrator.js';
|
|
45
|
+
import { loadToolPolicy, toolPolicyTemplate } from '../tools/ToolPolicy.js';
|
|
39
46
|
import { cleanupWorkspaceLifecycle, inspectWorkspaceLifecycle, } from '../workflow/WorkspaceLifecycle.js';
|
|
40
47
|
import { resolveWorkspaceTopology, workspaceTopologyPath, workspaceTopologyTemplate, } from '../workflow/WorkspaceTopology.js';
|
|
41
48
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
42
49
|
import { join, resolve } from 'node:path';
|
|
50
|
+
import { execFileSync } from 'node:child_process';
|
|
43
51
|
import { SCALE_ENGINE_VERSION } from '../version.js';
|
|
44
52
|
// ============================================================================
|
|
45
53
|
// Engine bootstrap (单例 + lazy init)
|
|
@@ -893,6 +901,52 @@ function printWorkspaceLifecycle(report) {
|
|
|
893
901
|
for (const action of report.finish.nextActions)
|
|
894
902
|
console.log(` [NEXT] ${action}`);
|
|
895
903
|
}
|
|
904
|
+
function compactList(values, limit = 5) {
|
|
905
|
+
if (values.length <= limit)
|
|
906
|
+
return values.join(', ');
|
|
907
|
+
return `${values.slice(0, limit).join(', ')} (+${values.length - limit} more)`;
|
|
908
|
+
}
|
|
909
|
+
function printWorkspaceSummary(report) {
|
|
910
|
+
const dirtyChildren = report.childRepositories
|
|
911
|
+
.filter(child => !child.clean)
|
|
912
|
+
.map(child => child.relativePath);
|
|
913
|
+
const unpushedChildren = report.childRepositories
|
|
914
|
+
.filter(child => child.ahead > 0 || (report.topology.finishPolicy.requirePushedBranches && report.topology.topology === 'moe' && !child.upstream && Boolean(child.branch)))
|
|
915
|
+
.map(child => child.relativePath);
|
|
916
|
+
const noUpstreamChildren = report.childRepositories
|
|
917
|
+
.filter(child => !child.upstream && Boolean(child.branch))
|
|
918
|
+
.map(child => child.relativePath);
|
|
919
|
+
const rootStatus = report.root.clean
|
|
920
|
+
? 'clean'
|
|
921
|
+
: `dirty (staged=${report.root.staged}, unstaged=${report.root.unstaged}, untracked=${report.root.untracked})`;
|
|
922
|
+
const status = report.finish.blockers.length > 0 ? 'BLOCKED' : 'READY';
|
|
923
|
+
console.log('\nSCALE Workspace Summary');
|
|
924
|
+
console.log(` Status: ${status}`);
|
|
925
|
+
console.log(` Topology: ${report.topology.topology}${report.topology.configured ? '' : ' (default)'}`);
|
|
926
|
+
console.log(` Root: ${rootStatus}`);
|
|
927
|
+
console.log(` Children: ${report.childRepositories.length} total, ${dirtyChildren.length} dirty, ${unpushedChildren.length} unpushed, ${noUpstreamChildren.length} no upstream`);
|
|
928
|
+
if (dirtyChildren.length > 0)
|
|
929
|
+
console.log(` Dirty child repositories: ${compactList(dirtyChildren)}`);
|
|
930
|
+
if (unpushedChildren.length > 0)
|
|
931
|
+
console.log(` Unpushed child repositories: ${compactList(unpushedChildren)}`);
|
|
932
|
+
if (report.finish.blockers.length > 0) {
|
|
933
|
+
console.log('\n Blockers:');
|
|
934
|
+
for (const blocker of report.finish.blockers.slice(0, 8))
|
|
935
|
+
console.log(` - ${blocker}`);
|
|
936
|
+
if (report.finish.blockers.length > 8)
|
|
937
|
+
console.log(` - ... ${report.finish.blockers.length - 8} more blocker(s)`);
|
|
938
|
+
}
|
|
939
|
+
if (report.finish.warnings.length > 0) {
|
|
940
|
+
console.log(`\n Warnings: ${report.finish.warnings.length} warning(s); run scale workspace finish --json for details`);
|
|
941
|
+
}
|
|
942
|
+
console.log('\n Next:');
|
|
943
|
+
const nextActions = report.finish.blockers.length > 0
|
|
944
|
+
? report.finish.nextActions
|
|
945
|
+
: ['Proceed with scale ship <task-id> or cleanup when the branch policy is satisfied'];
|
|
946
|
+
for (const action of nextActions.slice(0, 3))
|
|
947
|
+
console.log(` - ${action}`);
|
|
948
|
+
console.log(' - Run scale workspace finish --json for full details');
|
|
949
|
+
}
|
|
896
950
|
function printWorkspaceTopology(topology, written) {
|
|
897
951
|
console.log('\nSCALE Workspace Topology');
|
|
898
952
|
console.log(` Topology: ${topology.topology}${topology.configured ? '' : ' (default)'}`);
|
|
@@ -925,6 +979,7 @@ const workspaceStatus = defineCommand({
|
|
|
925
979
|
meta: { name: 'status', description: 'Inspect root worktree and child repository lifecycle state' },
|
|
926
980
|
args: {
|
|
927
981
|
dir: { type: 'string', description: 'Repository or worktree directory; defaults to current project directory' },
|
|
982
|
+
summary: { type: 'boolean', default: false, description: 'Print concise human summary instead of the full repository listing' },
|
|
928
983
|
json: { type: 'boolean', default: false },
|
|
929
984
|
},
|
|
930
985
|
async run({ args }) {
|
|
@@ -932,6 +987,9 @@ const workspaceStatus = defineCommand({
|
|
|
932
987
|
if (args.json) {
|
|
933
988
|
console.log(JSON.stringify(report, null, 2));
|
|
934
989
|
}
|
|
990
|
+
else if (isTruthyFlag(args.summary)) {
|
|
991
|
+
printWorkspaceSummary(report);
|
|
992
|
+
}
|
|
935
993
|
else {
|
|
936
994
|
printWorkspaceLifecycle(report);
|
|
937
995
|
}
|
|
@@ -972,6 +1030,7 @@ const workspaceFinish = defineCommand({
|
|
|
972
1030
|
meta: { name: 'finish', description: 'Check whether a temporary worktree can be safely finished or cleaned up' },
|
|
973
1031
|
args: {
|
|
974
1032
|
dir: { type: 'string', description: 'Repository or worktree directory; defaults to current project directory' },
|
|
1033
|
+
summary: { type: 'boolean', default: false, description: 'Print concise human summary instead of the full repository listing' },
|
|
975
1034
|
json: { type: 'boolean', default: false },
|
|
976
1035
|
},
|
|
977
1036
|
async run({ args }) {
|
|
@@ -985,6 +1044,9 @@ const workspaceFinish = defineCommand({
|
|
|
985
1044
|
if (args.json) {
|
|
986
1045
|
console.log(JSON.stringify(result, null, 2));
|
|
987
1046
|
}
|
|
1047
|
+
else if (isTruthyFlag(args.summary)) {
|
|
1048
|
+
printWorkspaceSummary(report);
|
|
1049
|
+
}
|
|
988
1050
|
else {
|
|
989
1051
|
printWorkspaceLifecycle(report);
|
|
990
1052
|
}
|
|
@@ -999,6 +1061,7 @@ const workspaceCleanup = defineCommand({
|
|
|
999
1061
|
'dry-run': { type: 'boolean', default: false, description: 'Preview cleanup; this is the default unless --apply is set' },
|
|
1000
1062
|
apply: { type: 'boolean', default: false, description: 'Actually run git worktree remove after safety checks' },
|
|
1001
1063
|
confirm: { type: 'string', description: 'Required confirmation token for --apply, usually the worktree branch name' },
|
|
1064
|
+
summary: { type: 'boolean', default: false, description: 'Print concise human summary before the cleanup plan' },
|
|
1002
1065
|
json: { type: 'boolean', default: false },
|
|
1003
1066
|
},
|
|
1004
1067
|
async run({ args }) {
|
|
@@ -1010,6 +1073,14 @@ const workspaceCleanup = defineCommand({
|
|
|
1010
1073
|
if (args.json) {
|
|
1011
1074
|
console.log(JSON.stringify(result, null, 2));
|
|
1012
1075
|
}
|
|
1076
|
+
else if (isTruthyFlag(args.summary)) {
|
|
1077
|
+
printWorkspaceSummary(result.report);
|
|
1078
|
+
console.log('\n Cleanup:');
|
|
1079
|
+
console.log(` Mode: ${result.mode}`);
|
|
1080
|
+
console.log(` Can apply: ${result.canApply ? 'yes' : 'no'}`);
|
|
1081
|
+
console.log(` Applied: ${result.applied ? 'yes' : 'no'}`);
|
|
1082
|
+
console.log(` Confirmation token: ${result.confirmationToken ?? '(unavailable)'}`);
|
|
1083
|
+
}
|
|
1013
1084
|
else {
|
|
1014
1085
|
printWorkspaceCleanup(result);
|
|
1015
1086
|
}
|
|
@@ -1559,14 +1630,48 @@ const assets = defineCommand({
|
|
|
1559
1630
|
// ============================================================================
|
|
1560
1631
|
// standards command - Engineering standards governance
|
|
1561
1632
|
// ============================================================================
|
|
1633
|
+
function resolveChangedFilesArg(args) {
|
|
1634
|
+
const explicit = splitChangedFiles(args['changed-files']);
|
|
1635
|
+
if (explicit.length > 0)
|
|
1636
|
+
return explicit;
|
|
1637
|
+
if (!args.changed)
|
|
1638
|
+
return undefined;
|
|
1639
|
+
return readGitChangedFiles(args.dir ?? '.');
|
|
1640
|
+
}
|
|
1641
|
+
function splitChangedFiles(value) {
|
|
1642
|
+
if (!value)
|
|
1643
|
+
return [];
|
|
1644
|
+
return value
|
|
1645
|
+
.split(/[\n,]/)
|
|
1646
|
+
.map(item => item.trim())
|
|
1647
|
+
.filter(Boolean);
|
|
1648
|
+
}
|
|
1649
|
+
function readGitChangedFiles(projectDir) {
|
|
1650
|
+
const tracked = readGitPathList(projectDir, ['diff', '--name-only', '--diff-filter=ACMRTUXB', 'HEAD', '--']);
|
|
1651
|
+
const untracked = readGitPathList(projectDir, ['ls-files', '--others', '--exclude-standard']);
|
|
1652
|
+
return Array.from(new Set([...tracked, ...untracked]));
|
|
1653
|
+
}
|
|
1654
|
+
function readGitPathList(projectDir, args) {
|
|
1655
|
+
try {
|
|
1656
|
+
return execFileSync('git', ['-C', projectDir, ...args], { encoding: 'utf-8' })
|
|
1657
|
+
.split(/\r?\n/)
|
|
1658
|
+
.map(item => item.trim())
|
|
1659
|
+
.filter(Boolean);
|
|
1660
|
+
}
|
|
1661
|
+
catch {
|
|
1662
|
+
return [];
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1562
1665
|
const standardsScan = defineCommand({
|
|
1563
1666
|
meta: { name: 'scan', description: 'Scan source files for engineering standard violations' },
|
|
1564
1667
|
args: {
|
|
1565
1668
|
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
1669
|
+
changed: { type: 'boolean', default: false, description: 'Scan changed Git files only' },
|
|
1670
|
+
'changed-files': { type: 'string', description: 'Comma or newline separated file list to scan' },
|
|
1566
1671
|
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
1567
1672
|
},
|
|
1568
1673
|
run({ args }) {
|
|
1569
|
-
const report = scanEngineeringStandards({ projectDir: args.dir });
|
|
1674
|
+
const report = scanEngineeringStandards({ projectDir: args.dir, changedFiles: resolveChangedFilesArg(args) });
|
|
1570
1675
|
if (args.json) {
|
|
1571
1676
|
console.log(JSON.stringify(report, null, 2));
|
|
1572
1677
|
return;
|
|
@@ -1588,10 +1693,12 @@ const standardsDoctor = defineCommand({
|
|
|
1588
1693
|
meta: { name: 'doctor', description: 'Find blocking engineering standards problems' },
|
|
1589
1694
|
args: {
|
|
1590
1695
|
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
1696
|
+
changed: { type: 'boolean', default: false, description: 'Scan changed Git files only' },
|
|
1697
|
+
'changed-files': { type: 'string', description: 'Comma or newline separated file list to scan' },
|
|
1591
1698
|
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
1592
1699
|
},
|
|
1593
1700
|
run({ args }) {
|
|
1594
|
-
const report = doctorEngineeringStandards({ projectDir: args.dir });
|
|
1701
|
+
const report = doctorEngineeringStandards({ projectDir: args.dir, changedFiles: resolveChangedFilesArg(args) });
|
|
1595
1702
|
if (args.json) {
|
|
1596
1703
|
console.log(JSON.stringify(report, null, 2));
|
|
1597
1704
|
if (!report.ok)
|
|
@@ -1619,6 +1726,8 @@ const standardsSettle = defineCommand({
|
|
|
1619
1726
|
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
1620
1727
|
'task-id': { type: 'string', description: 'Task id for the settlement record' },
|
|
1621
1728
|
'artifact-dir': { type: 'string', description: 'Task artifact directory where standards-impact.md should be updated' },
|
|
1729
|
+
changed: { type: 'boolean', default: false, description: 'Scan changed Git files only' },
|
|
1730
|
+
'changed-files': { type: 'string', description: 'Comma or newline separated file list to scan' },
|
|
1622
1731
|
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
1623
1732
|
},
|
|
1624
1733
|
run({ args }) {
|
|
@@ -1626,6 +1735,7 @@ const standardsSettle = defineCommand({
|
|
|
1626
1735
|
projectDir: args.dir,
|
|
1627
1736
|
taskId: args['task-id'],
|
|
1628
1737
|
artifactsDir: args['artifact-dir'],
|
|
1738
|
+
changedFiles: resolveChangedFilesArg(args),
|
|
1629
1739
|
});
|
|
1630
1740
|
if (args.json) {
|
|
1631
1741
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -1643,9 +1753,41 @@ const standardsSettle = defineCommand({
|
|
|
1643
1753
|
process.exitCode = 1;
|
|
1644
1754
|
},
|
|
1645
1755
|
});
|
|
1756
|
+
const standardsBaseline = defineCommand({
|
|
1757
|
+
meta: { name: 'baseline', description: 'Generate a legacy standards baseline and classification report' },
|
|
1758
|
+
args: {
|
|
1759
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
1760
|
+
write: { type: 'boolean', default: false, description: 'Write .scale/engineering-standards-baseline.json' },
|
|
1761
|
+
'task-id': { type: 'string', description: 'Task id for the legacy debt report' },
|
|
1762
|
+
'artifact-dir': { type: 'string', description: 'Directory where standards-legacy-debt.md should be written' },
|
|
1763
|
+
reason: { type: 'string', default: 'legacy standards debt accepted for staged remediation', description: 'Reason recorded on generated baseline entries' },
|
|
1764
|
+
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
1765
|
+
},
|
|
1766
|
+
run({ args }) {
|
|
1767
|
+
const report = baselineEngineeringStandards({
|
|
1768
|
+
projectDir: args.dir,
|
|
1769
|
+
writeBaseline: args.write,
|
|
1770
|
+
taskId: args['task-id'],
|
|
1771
|
+
artifactsDir: args['artifact-dir'],
|
|
1772
|
+
reason: args.reason,
|
|
1773
|
+
});
|
|
1774
|
+
if (args.json) {
|
|
1775
|
+
console.log(JSON.stringify(report, null, 2));
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
console.log(`Standards baseline: ${report.wroteBaseline ? 'written' : 'dry-run'}`);
|
|
1779
|
+
console.log(` Baseline entries: ${report.baselineEntries.length}`);
|
|
1780
|
+
console.log(` Blocking findings: ${report.debt.blockingFindings}`);
|
|
1781
|
+
console.log(` Baseline path: ${report.baselinePath}`);
|
|
1782
|
+
if (report.legacyDebtPath)
|
|
1783
|
+
console.log(` Legacy debt report: ${report.legacyDebtPath}`);
|
|
1784
|
+
if (!report.wroteBaseline)
|
|
1785
|
+
console.log(' Re-run with --write to update .scale/engineering-standards-baseline.json.');
|
|
1786
|
+
},
|
|
1787
|
+
});
|
|
1646
1788
|
const standards = defineCommand({
|
|
1647
1789
|
meta: { name: 'standards', description: 'Engineering standards governance for logs, security, architecture, database, and code quality' },
|
|
1648
|
-
subCommands: { scan: standardsScan, doctor: standardsDoctor, settle: standardsSettle },
|
|
1790
|
+
subCommands: { scan: standardsScan, doctor: standardsDoctor, settle: standardsSettle, baseline: standardsBaseline },
|
|
1649
1791
|
});
|
|
1650
1792
|
// ============================================================================
|
|
1651
1793
|
// evolve command
|
|
@@ -2083,9 +2225,331 @@ const skillCheckCommand = defineCommand({
|
|
|
2083
2225
|
process.exitCode = 1;
|
|
2084
2226
|
},
|
|
2085
2227
|
});
|
|
2228
|
+
const skillRepoCommand = defineCommand({
|
|
2229
|
+
meta: { name: 'repo', description: 'Show SCALE progressive skill repository guide' },
|
|
2230
|
+
args: {
|
|
2231
|
+
category: { type: 'string', description: 'Filter by category: ui/browser/desktop/testing/review/docs/agent-cli/role-library/discovery' },
|
|
2232
|
+
output: { type: 'string', alias: 'o', description: 'Write markdown guide to file' },
|
|
2233
|
+
json: { type: 'boolean', default: false },
|
|
2234
|
+
},
|
|
2235
|
+
run({ args }) {
|
|
2236
|
+
if (args.json) {
|
|
2237
|
+
console.log(JSON.stringify(listSkillRepositoryEntries(args.category ? { category: args.category } : undefined), null, 2));
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
const markdown = renderSkillRepositoryMarkdown();
|
|
2241
|
+
if (args.output) {
|
|
2242
|
+
const outputPath = resolve(PROJECT_DIR, args.output);
|
|
2243
|
+
ensureDir(resolve(outputPath, '..'));
|
|
2244
|
+
writeFileSync(outputPath, markdown, 'utf-8');
|
|
2245
|
+
console.log(`[OK] Skill 仓库指南已生成: ${outputPath}`);
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
console.log(markdown);
|
|
2249
|
+
},
|
|
2250
|
+
});
|
|
2251
|
+
const skillSafetyCommand = defineCommand({
|
|
2252
|
+
meta: { name: 'safety', description: 'Evaluate skill install command and source safety' },
|
|
2253
|
+
args: {
|
|
2254
|
+
source: { type: 'string', description: 'Skill source URL' },
|
|
2255
|
+
command: { type: 'string', description: 'Install command to review' },
|
|
2256
|
+
json: { type: 'boolean', default: false },
|
|
2257
|
+
},
|
|
2258
|
+
run({ args }) {
|
|
2259
|
+
const report = evaluateSkillInstallSafety({
|
|
2260
|
+
sourceUrl: args.source,
|
|
2261
|
+
installCommand: args.command,
|
|
2262
|
+
});
|
|
2263
|
+
if (args.json) {
|
|
2264
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
console.log('\nSCALE Skill Safety');
|
|
2268
|
+
console.log(` Risk: ${report.risk}`);
|
|
2269
|
+
console.log(` Blocked: ${report.blocked}`);
|
|
2270
|
+
for (const finding of report.findings) {
|
|
2271
|
+
console.log(` [${finding.severity.toUpperCase()}] ${finding.rule}: ${finding.message}`);
|
|
2272
|
+
}
|
|
2273
|
+
console.log(' Required checks:');
|
|
2274
|
+
for (const check of report.requiredChecks)
|
|
2275
|
+
console.log(` - ${check}`);
|
|
2276
|
+
if (report.blocked)
|
|
2277
|
+
process.exitCode = 1;
|
|
2278
|
+
},
|
|
2279
|
+
});
|
|
2280
|
+
const skillRecommendCommand = defineCommand({
|
|
2281
|
+
meta: { name: 'recommend', description: 'Recommend a composable skill workflow for a task' },
|
|
2282
|
+
args: {
|
|
2283
|
+
task: { type: 'string', required: true, description: 'Task description' },
|
|
2284
|
+
phase: { type: 'string', description: 'Workflow phase' },
|
|
2285
|
+
json: { type: 'boolean', default: false },
|
|
2286
|
+
},
|
|
2287
|
+
run({ args }) {
|
|
2288
|
+
const plan = recommendSkillWorkflow({
|
|
2289
|
+
description: args.task,
|
|
2290
|
+
phase: args.phase,
|
|
2291
|
+
});
|
|
2292
|
+
if (args.json) {
|
|
2293
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
console.log('\nSCALE Skill Recommendation');
|
|
2297
|
+
console.log(` Primary: ${plan.primarySkills.join(', ') || 'none'}`);
|
|
2298
|
+
console.log(` Supporting: ${plan.supportingSkills.join(', ') || 'none'}`);
|
|
2299
|
+
console.log(` Safety required: ${plan.safetyRequired}`);
|
|
2300
|
+
console.log(` Evidence: ${plan.requiredEvidence.join(', ') || 'none'}`);
|
|
2301
|
+
for (const reason of plan.rationale)
|
|
2302
|
+
console.log(` - ${reason}`);
|
|
2303
|
+
},
|
|
2304
|
+
});
|
|
2086
2305
|
const skill = defineCommand({
|
|
2087
2306
|
meta: { name: 'skill', description: 'Skill discovery and management' },
|
|
2088
|
-
subCommands: {
|
|
2307
|
+
subCommands: {
|
|
2308
|
+
scan: skillScan,
|
|
2309
|
+
doctor: skillDoctorCommand,
|
|
2310
|
+
plan: skillPlanCommand,
|
|
2311
|
+
check: skillCheckCommand,
|
|
2312
|
+
repo: skillRepoCommand,
|
|
2313
|
+
safety: skillSafetyCommand,
|
|
2314
|
+
recommend: skillRecommendCommand,
|
|
2315
|
+
},
|
|
2316
|
+
});
|
|
2317
|
+
// ============================================================================
|
|
2318
|
+
// tool command - Skills/MCP/CLI orchestration governance
|
|
2319
|
+
// ============================================================================
|
|
2320
|
+
function normalizeToolMode(value) {
|
|
2321
|
+
const normalized = String(value ?? 'evidence-required');
|
|
2322
|
+
if (normalized === 'off' || normalized === 'advisory' || normalized === 'evidence-required' || normalized === 'block')
|
|
2323
|
+
return normalized;
|
|
2324
|
+
return 'evidence-required';
|
|
2325
|
+
}
|
|
2326
|
+
function parseToolIds(value) {
|
|
2327
|
+
const raw = String(value ?? '').trim();
|
|
2328
|
+
if (!raw)
|
|
2329
|
+
return undefined;
|
|
2330
|
+
return raw.split(',').map(item => item.trim()).filter(Boolean);
|
|
2331
|
+
}
|
|
2332
|
+
function parseCommaList(value) {
|
|
2333
|
+
return parseToolIds(value) ?? [];
|
|
2334
|
+
}
|
|
2335
|
+
function createToolExecutionPlanFromArgs(args) {
|
|
2336
|
+
const projectDir = resolve(String(args.dir ?? PROJECT_DIR));
|
|
2337
|
+
const level = normalizeTaskArtifactLevel(args.level ?? 'M');
|
|
2338
|
+
const skillPolicy = loadSkillRoutingPolicy(projectDir, SCALE_DIR);
|
|
2339
|
+
const skillPlan = createSkillPlan({
|
|
2340
|
+
taskId: String(args['task-id'] ?? `TOOL-${Date.now()}`),
|
|
2341
|
+
taskName: String(args.task ?? 'Tool orchestration task'),
|
|
2342
|
+
description: String(args.task ?? ''),
|
|
2343
|
+
level,
|
|
2344
|
+
files: parseCommaList(args.files),
|
|
2345
|
+
services: parseCommaList(args.services),
|
|
2346
|
+
policy: skillPolicy,
|
|
2347
|
+
});
|
|
2348
|
+
const toolPolicy = loadToolPolicy(projectDir, SCALE_DIR);
|
|
2349
|
+
const toolIds = uniqueStrings([
|
|
2350
|
+
...skillPlan.requiredSkills,
|
|
2351
|
+
...skillPlan.recommendedSkills,
|
|
2352
|
+
...Object.keys(toolPolicy.tools).filter(toolId => {
|
|
2353
|
+
const config = toolPolicy.tools[toolId];
|
|
2354
|
+
const domains = new Set(skillPlan.intents.map(intent => intent.domain));
|
|
2355
|
+
return config.enabled && (config.requiredFor.some(domain => domains.has(domain)) ||
|
|
2356
|
+
(config.recommendedFor ?? []).some(domain => domains.has(domain)));
|
|
2357
|
+
}),
|
|
2358
|
+
]);
|
|
2359
|
+
const capabilityReport = inspectToolCapabilities({
|
|
2360
|
+
projectDir,
|
|
2361
|
+
toolIds,
|
|
2362
|
+
});
|
|
2363
|
+
const orchestrator = new ToolOrchestrator({
|
|
2364
|
+
projectDir,
|
|
2365
|
+
policy: toolPolicy,
|
|
2366
|
+
capabilityReport,
|
|
2367
|
+
evidenceStore: new ToolEvidenceStore({ projectDir, scaleDir: SCALE_DIR }),
|
|
2368
|
+
});
|
|
2369
|
+
return {
|
|
2370
|
+
projectDir,
|
|
2371
|
+
skillPlan,
|
|
2372
|
+
orchestrator,
|
|
2373
|
+
plan: orchestrator.plan({ skillPlan }),
|
|
2374
|
+
capabilityReport,
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
function uniqueStrings(items) {
|
|
2378
|
+
return [...new Set(items)];
|
|
2379
|
+
}
|
|
2380
|
+
const toolPolicyCommand = defineCommand({
|
|
2381
|
+
meta: { name: 'policy', description: 'Show resolved tool orchestration policy' },
|
|
2382
|
+
args: {
|
|
2383
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2384
|
+
mode: { type: 'string', description: 'Render a starter policy mode instead of reading .scale/tools.json' },
|
|
2385
|
+
json: { type: 'boolean', default: false },
|
|
2386
|
+
},
|
|
2387
|
+
run({ args }) {
|
|
2388
|
+
const policy = args.mode
|
|
2389
|
+
? JSON.parse(toolPolicyTemplate(normalizeToolMode(args.mode)))
|
|
2390
|
+
: loadToolPolicy(args.dir, SCALE_DIR);
|
|
2391
|
+
if (args.json) {
|
|
2392
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
console.log('\nSCALE Tool Policy');
|
|
2396
|
+
console.log(` Mode: ${policy.mode}`);
|
|
2397
|
+
console.log(` Tools: ${Object.keys(policy.tools).length}`);
|
|
2398
|
+
for (const [id, config] of Object.entries(policy.tools)) {
|
|
2399
|
+
const state = config.enabled ? '[ON]' : '[OFF]';
|
|
2400
|
+
console.log(` ${state} ${id}: requiredFor=${config.requiredFor.join(',') || 'none'}`);
|
|
2401
|
+
}
|
|
2402
|
+
},
|
|
2403
|
+
});
|
|
2404
|
+
const toolDoctorCommand = defineCommand({
|
|
2405
|
+
meta: { name: 'doctor', description: 'Check skill, MCP, and CLI tool availability' },
|
|
2406
|
+
args: {
|
|
2407
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2408
|
+
tools: { type: 'string', description: 'Comma-separated tool ids to check' },
|
|
2409
|
+
json: { type: 'boolean', default: false },
|
|
2410
|
+
},
|
|
2411
|
+
run({ args }) {
|
|
2412
|
+
const report = inspectToolCapabilities({
|
|
2413
|
+
projectDir: args.dir,
|
|
2414
|
+
toolIds: parseToolIds(args.tools),
|
|
2415
|
+
});
|
|
2416
|
+
if (args.json) {
|
|
2417
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2418
|
+
}
|
|
2419
|
+
else {
|
|
2420
|
+
console.log('\nSCALE Tool Doctor');
|
|
2421
|
+
console.log(` Installed: ${report.summary.installed}/${report.summary.total}`);
|
|
2422
|
+
for (const entry of report.tools) {
|
|
2423
|
+
console.log(` ${entry.installed ? '[OK]' : '[MISSING]'} ${entry.id}`);
|
|
2424
|
+
if (entry.detectedPath)
|
|
2425
|
+
console.log(` path: ${entry.detectedPath}`);
|
|
2426
|
+
if (entry.version)
|
|
2427
|
+
console.log(` version: ${entry.version}`);
|
|
2428
|
+
if (entry.missingReason)
|
|
2429
|
+
console.log(` reason: ${entry.missingReason}`);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
if (!report.ok)
|
|
2433
|
+
process.exitCode = 1;
|
|
2434
|
+
},
|
|
2435
|
+
});
|
|
2436
|
+
const toolPlanCommand = defineCommand({
|
|
2437
|
+
meta: { name: 'plan', description: 'Create a tool execution plan from task intent' },
|
|
2438
|
+
args: {
|
|
2439
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2440
|
+
'task-id': { type: 'string', required: true, description: 'Task id for evidence linkage' },
|
|
2441
|
+
task: { type: 'string', required: true, description: 'Task description' },
|
|
2442
|
+
level: { type: 'string', default: 'M', description: 'Task level: S, M, L, or CRITICAL' },
|
|
2443
|
+
files: { type: 'string', description: 'Comma-separated changed or target files' },
|
|
2444
|
+
services: { type: 'string', description: 'Comma-separated affected services' },
|
|
2445
|
+
json: { type: 'boolean', default: false },
|
|
2446
|
+
},
|
|
2447
|
+
run({ args }) {
|
|
2448
|
+
const result = createToolExecutionPlanFromArgs(args);
|
|
2449
|
+
if (args.json) {
|
|
2450
|
+
console.log(JSON.stringify(result.plan, null, 2));
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2453
|
+
console.log('\nSCALE Tool Plan');
|
|
2454
|
+
console.log(` Task: ${result.plan.taskId}`);
|
|
2455
|
+
console.log(` Mode: ${result.plan.mode}`);
|
|
2456
|
+
console.log(` Steps: ${result.plan.steps.length}`);
|
|
2457
|
+
for (const step of result.plan.steps) {
|
|
2458
|
+
console.log(` ${step.status === 'ready' ? '[READY]' : '[MISSING]'} ${step.toolId} (${step.adapter}) required=${step.required}`);
|
|
2459
|
+
}
|
|
2460
|
+
for (const blocker of result.plan.blockers)
|
|
2461
|
+
console.log(` [BLOCKER] ${blocker}`);
|
|
2462
|
+
for (const warning of result.plan.warnings)
|
|
2463
|
+
console.log(` [WARN] ${warning}`);
|
|
2464
|
+
},
|
|
2465
|
+
});
|
|
2466
|
+
const toolRunCommand = defineCommand({
|
|
2467
|
+
meta: { name: 'run', description: 'Run or dry-run a tool execution plan and write tool evidence' },
|
|
2468
|
+
args: {
|
|
2469
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2470
|
+
'task-id': { type: 'string', required: true, description: 'Task id for evidence linkage' },
|
|
2471
|
+
task: { type: 'string', required: true, description: 'Task description' },
|
|
2472
|
+
level: { type: 'string', default: 'M', description: 'Task level: S, M, L, or CRITICAL' },
|
|
2473
|
+
files: { type: 'string', description: 'Comma-separated changed or target files' },
|
|
2474
|
+
services: { type: 'string', description: 'Comma-separated affected services' },
|
|
2475
|
+
'dry-run': { type: 'boolean', default: false, description: 'Plan and record skipped evidence without executing tools' },
|
|
2476
|
+
json: { type: 'boolean', default: false },
|
|
2477
|
+
},
|
|
2478
|
+
async run({ args }) {
|
|
2479
|
+
const result = createToolExecutionPlanFromArgs(args);
|
|
2480
|
+
const report = await result.orchestrator.run(result.plan, {
|
|
2481
|
+
dryRun: isTruthyFlag(args['dry-run']),
|
|
2482
|
+
});
|
|
2483
|
+
if (args.json) {
|
|
2484
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2485
|
+
}
|
|
2486
|
+
else {
|
|
2487
|
+
console.log('\nSCALE Tool Run');
|
|
2488
|
+
console.log(` Task: ${report.taskId}`);
|
|
2489
|
+
console.log(` Dry-run: ${report.dryRun}`);
|
|
2490
|
+
console.log(` Evidence: ${report.evidence.length}`);
|
|
2491
|
+
for (const record of report.evidence) {
|
|
2492
|
+
console.log(` [${record.status.toUpperCase()}] ${record.tool} -> ${record.id}`);
|
|
2493
|
+
}
|
|
2494
|
+
for (const blocker of report.blockers)
|
|
2495
|
+
console.log(` [BLOCKER] ${blocker}`);
|
|
2496
|
+
for (const warning of report.warnings)
|
|
2497
|
+
console.log(` [WARN] ${warning}`);
|
|
2498
|
+
}
|
|
2499
|
+
if (!report.ok)
|
|
2500
|
+
process.exitCode = 1;
|
|
2501
|
+
},
|
|
2502
|
+
});
|
|
2503
|
+
const toolEvidenceCommand = defineCommand({
|
|
2504
|
+
meta: { name: 'evidence', description: 'Check required tool execution evidence for a task' },
|
|
2505
|
+
args: {
|
|
2506
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
2507
|
+
'task-id': { type: 'string', required: true, description: 'Task id for evidence linkage' },
|
|
2508
|
+
task: { type: 'string', required: true, description: 'Task description' },
|
|
2509
|
+
level: { type: 'string', default: 'M', description: 'Task level: S, M, L, or CRITICAL' },
|
|
2510
|
+
files: { type: 'string', description: 'Comma-separated changed or target files' },
|
|
2511
|
+
services: { type: 'string', description: 'Comma-separated affected services' },
|
|
2512
|
+
mode: { type: 'string', description: 'Override tool gate mode: off, advisory, evidence-required, or block' },
|
|
2513
|
+
'allow-skipped': { type: 'boolean', default: false, description: 'Allow skipped/manual fallback evidence to satisfy required tools' },
|
|
2514
|
+
json: { type: 'boolean', default: false },
|
|
2515
|
+
},
|
|
2516
|
+
run({ args }) {
|
|
2517
|
+
const result = createToolExecutionPlanFromArgs(args);
|
|
2518
|
+
const gate = evaluateToolEvidenceGate({
|
|
2519
|
+
projectDir: result.projectDir,
|
|
2520
|
+
level: normalizeTaskArtifactLevel(args.level ?? 'M'),
|
|
2521
|
+
plan: result.plan,
|
|
2522
|
+
evidenceStore: new ToolEvidenceStore({ projectDir: result.projectDir, scaleDir: SCALE_DIR }),
|
|
2523
|
+
mode: args.mode ? normalizeToolMode(args.mode) : result.plan.mode,
|
|
2524
|
+
allowSkipped: isTruthyFlag(args['allow-skipped']),
|
|
2525
|
+
});
|
|
2526
|
+
if (args.json) {
|
|
2527
|
+
console.log(JSON.stringify(gate, null, 2));
|
|
2528
|
+
}
|
|
2529
|
+
else {
|
|
2530
|
+
console.log('\nSCALE Tool Evidence Gate');
|
|
2531
|
+
console.log(` Task: ${gate.taskId ?? args['task-id']}`);
|
|
2532
|
+
console.log(` Mode: ${gate.mode}`);
|
|
2533
|
+
console.log(` Complete: ${gate.complete}`);
|
|
2534
|
+
console.log(` Required tools: ${gate.requiredTools.join(', ') || 'none'}`);
|
|
2535
|
+
for (const item of gate.missing)
|
|
2536
|
+
console.log(` [MISSING] ${item.toolId}: ${item.reason}`);
|
|
2537
|
+
for (const item of gate.failed)
|
|
2538
|
+
console.log(` [FAILED] ${item.toolId}: ${item.reason}`);
|
|
2539
|
+
for (const item of gate.skipped)
|
|
2540
|
+
console.log(` [SKIPPED] ${item.toolId}: ${item.reason}`);
|
|
2541
|
+
for (const item of gate.passed)
|
|
2542
|
+
console.log(` [PASS] ${item.toolId}: ${item.evidenceId ?? 'evidence'}`);
|
|
2543
|
+
for (const warning of gate.warnings)
|
|
2544
|
+
console.log(` [WARN] ${warning}`);
|
|
2545
|
+
}
|
|
2546
|
+
if (gate.blocked)
|
|
2547
|
+
process.exitCode = 1;
|
|
2548
|
+
},
|
|
2549
|
+
});
|
|
2550
|
+
const tool = defineCommand({
|
|
2551
|
+
meta: { name: 'tool', description: 'Skills, MCP, browser, desktop, and external CLI governance' },
|
|
2552
|
+
subCommands: { policy: toolPolicyCommand, doctor: toolDoctorCommand, plan: toolPlanCommand, run: toolRunCommand, evidence: toolEvidenceCommand },
|
|
2089
2553
|
});
|
|
2090
2554
|
// ============================================================================
|
|
2091
2555
|
// agent commands — Multi-Agent 协作系统 (Phase 9)
|
|
@@ -2142,9 +2606,32 @@ const agentProfiles = defineCommand({
|
|
|
2142
2606
|
}
|
|
2143
2607
|
},
|
|
2144
2608
|
});
|
|
2609
|
+
const agentLeaders = defineCommand({
|
|
2610
|
+
meta: { name: 'leaders', description: 'List SCALE leader presets such as CEO and CTO' },
|
|
2611
|
+
args: {
|
|
2612
|
+
output: { type: 'string', alias: 'o', description: 'Write markdown guide to file' },
|
|
2613
|
+
json: { type: 'boolean', default: false },
|
|
2614
|
+
},
|
|
2615
|
+
async run({ args }) {
|
|
2616
|
+
const presets = listLeadershipPresets();
|
|
2617
|
+
if (args.json) {
|
|
2618
|
+
console.log(JSON.stringify(presets, null, 2));
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
const markdown = renderLeadershipPresetsMarkdown();
|
|
2622
|
+
if (args.output) {
|
|
2623
|
+
const outputPath = resolve(PROJECT_DIR, args.output);
|
|
2624
|
+
ensureDir(resolve(outputPath, '..'));
|
|
2625
|
+
writeFileSync(outputPath, markdown, 'utf-8');
|
|
2626
|
+
console.log(`[OK] 领导者角色指南已生成: ${outputPath}`);
|
|
2627
|
+
return;
|
|
2628
|
+
}
|
|
2629
|
+
console.log(markdown);
|
|
2630
|
+
},
|
|
2631
|
+
});
|
|
2145
2632
|
const agent = defineCommand({
|
|
2146
2633
|
meta: { name: 'agent', description: 'Multi-Agent system management' },
|
|
2147
|
-
subCommands: { spawn: agentSpawn, list: agentList, profiles: agentProfiles },
|
|
2634
|
+
subCommands: { spawn: agentSpawn, list: agentList, profiles: agentProfiles, leaders: agentLeaders },
|
|
2148
2635
|
});
|
|
2149
2636
|
// ============================================================================
|
|
2150
2637
|
// team commands — 团队协作 (Phase 9)
|
|
@@ -2250,6 +2737,7 @@ const main = defineCommand({
|
|
|
2250
2737
|
status,
|
|
2251
2738
|
workflow,
|
|
2252
2739
|
evidence,
|
|
2740
|
+
tool,
|
|
2253
2741
|
skill,
|
|
2254
2742
|
skills: skill,
|
|
2255
2743
|
agent,
|