@hongmaple0820/scale-engine 0.15.0 → 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.
Files changed (89) hide show
  1. package/README.en.md +13 -5
  2. package/README.md +13 -5
  3. package/dist/agents/LeadershipPresets.d.ts +16 -0
  4. package/dist/agents/LeadershipPresets.js +152 -0
  5. package/dist/agents/LeadershipPresets.js.map +1 -0
  6. package/dist/api/cli.js +729 -5
  7. package/dist/api/cli.js.map +1 -1
  8. package/dist/api/doctor.d.ts +2 -0
  9. package/dist/api/doctor.js +83 -0
  10. package/dist/api/doctor.js.map +1 -1
  11. package/dist/api/mcp.js +2 -1
  12. package/dist/api/mcp.js.map +1 -1
  13. package/dist/artifact/types.d.ts +4 -0
  14. package/dist/artifact/types.js.map +1 -1
  15. package/dist/capabilities/InstalledSkillsIntegration.d.ts +3 -0
  16. package/dist/capabilities/InstalledSkillsIntegration.js +41 -17
  17. package/dist/capabilities/InstalledSkillsIntegration.js.map +1 -1
  18. package/dist/cli/phaseCommands.d.ts +14 -0
  19. package/dist/cli/phaseCommands.js +214 -5
  20. package/dist/cli/phaseCommands.js.map +1 -1
  21. package/dist/cli/vibeCommands.d.ts +20 -0
  22. package/dist/cli/vibeCommands.js +150 -173
  23. package/dist/cli/vibeCommands.js.map +1 -1
  24. package/dist/core/logger.d.ts +2 -0
  25. package/dist/core/logger.js +33 -1
  26. package/dist/core/logger.js.map +1 -1
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.js +5 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/output/HTMLDocumentRenderer.js +3 -2
  31. package/dist/output/HTMLDocumentRenderer.js.map +1 -1
  32. package/dist/prompts/VibeTemplateGallery.d.ts +25 -0
  33. package/dist/prompts/VibeTemplateGallery.js +295 -0
  34. package/dist/prompts/VibeTemplateGallery.js.map +1 -0
  35. package/dist/skills/ExternalSkills.js +9 -4
  36. package/dist/skills/ExternalSkills.js.map +1 -1
  37. package/dist/skills/SkillDiscovery.js +5 -3
  38. package/dist/skills/SkillDiscovery.js.map +1 -1
  39. package/dist/skills/SkillDoctor.js +178 -1
  40. package/dist/skills/SkillDoctor.js.map +1 -1
  41. package/dist/skills/SkillInstaller.js +5 -0
  42. package/dist/skills/SkillInstaller.js.map +1 -1
  43. package/dist/skills/SkillRepository.d.ts +63 -0
  44. package/dist/skills/SkillRepository.js +365 -0
  45. package/dist/skills/SkillRepository.js.map +1 -0
  46. package/dist/skills/routing/SkillPolicy.js +168 -5
  47. package/dist/skills/routing/SkillPolicy.js.map +1 -1
  48. package/dist/tools/ToolCapabilityRegistry.d.ts +46 -0
  49. package/dist/tools/ToolCapabilityRegistry.js +223 -0
  50. package/dist/tools/ToolCapabilityRegistry.js.map +1 -0
  51. package/dist/tools/ToolEvidenceGate.d.ts +39 -0
  52. package/dist/tools/ToolEvidenceGate.js +117 -0
  53. package/dist/tools/ToolEvidenceGate.js.map +1 -0
  54. package/dist/tools/ToolEvidenceStore.d.ts +58 -0
  55. package/dist/tools/ToolEvidenceStore.js +129 -0
  56. package/dist/tools/ToolEvidenceStore.js.map +1 -0
  57. package/dist/tools/ToolOrchestrator.d.ts +67 -0
  58. package/dist/tools/ToolOrchestrator.js +193 -0
  59. package/dist/tools/ToolOrchestrator.js.map +1 -0
  60. package/dist/tools/ToolPolicy.d.ts +33 -0
  61. package/dist/tools/ToolPolicy.js +157 -0
  62. package/dist/tools/ToolPolicy.js.map +1 -0
  63. package/dist/tools/index.d.ts +5 -0
  64. package/dist/tools/index.js +6 -0
  65. package/dist/tools/index.js.map +1 -0
  66. package/dist/version.d.ts +3 -0
  67. package/dist/version.js +15 -0
  68. package/dist/version.js.map +1 -0
  69. package/dist/workflow/EngineeringStandards.d.ts +212 -0
  70. package/dist/workflow/EngineeringStandards.js +1021 -0
  71. package/dist/workflow/EngineeringStandards.js.map +1 -0
  72. package/dist/workflow/GovernanceTemplatePacks.d.ts +1 -1
  73. package/dist/workflow/GovernanceTemplatePacks.js +101 -18
  74. package/dist/workflow/GovernanceTemplatePacks.js.map +1 -1
  75. package/dist/workflow/GovernanceTemplates.d.ts +1 -1
  76. package/dist/workflow/GovernanceTemplates.js +225 -37
  77. package/dist/workflow/GovernanceTemplates.js.map +1 -1
  78. package/dist/workflow/ResourceGovernance.d.ts +120 -0
  79. package/dist/workflow/ResourceGovernance.js +512 -0
  80. package/dist/workflow/ResourceGovernance.js.map +1 -0
  81. package/dist/workflow/TaskArtifactScaffolder.js +3 -0
  82. package/dist/workflow/TaskArtifactScaffolder.js.map +1 -1
  83. package/dist/workflow/VerificationProfile.d.ts +2 -0
  84. package/dist/workflow/VerificationProfile.js +7 -0
  85. package/dist/workflow/VerificationProfile.js.map +1 -1
  86. package/dist/workflow/index.d.ts +2 -0
  87. package/dist/workflow/index.js +2 -0
  88. package/dist/workflow/index.js.map +1 -1
  89. 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,13 +33,22 @@ 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';
36
+ import { baselineEngineeringStandards, doctorEngineeringStandards, scanEngineeringStandards, settleEngineeringStandards, } from '../workflow/EngineeringStandards.js';
37
+ import { doctorResourceAssets, scanResourceAssets, settleResourceAssets } from '../workflow/ResourceGovernance.js';
34
38
  import { TaskMetricsStore } from '../workflow/TaskMetricsStore.js';
35
39
  import { checkTaskArtifactCompleteness } from '../workflow/TaskArtifactScaffolder.js';
36
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';
37
46
  import { cleanupWorkspaceLifecycle, inspectWorkspaceLifecycle, } from '../workflow/WorkspaceLifecycle.js';
38
47
  import { resolveWorkspaceTopology, workspaceTopologyPath, workspaceTopologyTemplate, } from '../workflow/WorkspaceTopology.js';
39
48
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
40
49
  import { join, resolve } from 'node:path';
50
+ import { execFileSync } from 'node:child_process';
51
+ import { SCALE_ENGINE_VERSION } from '../version.js';
41
52
  // ============================================================================
42
53
  // Engine bootstrap (单例 + lazy init)
43
54
  // ============================================================================
@@ -69,6 +80,42 @@ function gatesForPreflightProfile(profile) {
69
80
  return ['G3', 'G0', 'G4', 'G5'];
70
81
  return ['G3', 'G0', 'G4', 'G5', 'G6', 'G7'];
71
82
  }
83
+ function evaluateEngineeringStandardsGate(options) {
84
+ const mode = normalizeEngineeringStandardsGateMode(options.policy.engineeringStandardsGate);
85
+ if (mode === 'off') {
86
+ return {
87
+ mode,
88
+ checked: false,
89
+ blocked: false,
90
+ ok: true,
91
+ findings: [],
92
+ };
93
+ }
94
+ const settlement = options.settle && options.artifactsDir
95
+ ? settleEngineeringStandards({
96
+ projectDir: PROJECT_DIR,
97
+ scaleDir: SCALE_DIR,
98
+ taskId: options.taskId,
99
+ artifactsDir: options.artifactsDir,
100
+ })
101
+ : undefined;
102
+ const doctor = settlement?.doctor ?? doctorEngineeringStandards({
103
+ projectDir: PROJECT_DIR,
104
+ scaleDir: SCALE_DIR,
105
+ });
106
+ return {
107
+ mode,
108
+ checked: true,
109
+ blocked: mode === 'block' && !doctor.ok,
110
+ ok: doctor.ok,
111
+ findings: doctor.findings,
112
+ summary: doctor.scan.summary,
113
+ standardsImpactPath: settlement?.standardsImpactPath,
114
+ };
115
+ }
116
+ function normalizeEngineeringStandardsGateMode(value) {
117
+ return value === 'off' || value === 'block' ? value : 'warn';
118
+ }
72
119
  let _engine = null;
73
120
  function getEngine() {
74
121
  if (!_engine)
@@ -854,6 +901,52 @@ function printWorkspaceLifecycle(report) {
854
901
  for (const action of report.finish.nextActions)
855
902
  console.log(` [NEXT] ${action}`);
856
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
+ }
857
950
  function printWorkspaceTopology(topology, written) {
858
951
  console.log('\nSCALE Workspace Topology');
859
952
  console.log(` Topology: ${topology.topology}${topology.configured ? '' : ' (default)'}`);
@@ -886,6 +979,7 @@ const workspaceStatus = defineCommand({
886
979
  meta: { name: 'status', description: 'Inspect root worktree and child repository lifecycle state' },
887
980
  args: {
888
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' },
889
983
  json: { type: 'boolean', default: false },
890
984
  },
891
985
  async run({ args }) {
@@ -893,6 +987,9 @@ const workspaceStatus = defineCommand({
893
987
  if (args.json) {
894
988
  console.log(JSON.stringify(report, null, 2));
895
989
  }
990
+ else if (isTruthyFlag(args.summary)) {
991
+ printWorkspaceSummary(report);
992
+ }
896
993
  else {
897
994
  printWorkspaceLifecycle(report);
898
995
  }
@@ -933,6 +1030,7 @@ const workspaceFinish = defineCommand({
933
1030
  meta: { name: 'finish', description: 'Check whether a temporary worktree can be safely finished or cleaned up' },
934
1031
  args: {
935
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' },
936
1034
  json: { type: 'boolean', default: false },
937
1035
  },
938
1036
  async run({ args }) {
@@ -946,6 +1044,9 @@ const workspaceFinish = defineCommand({
946
1044
  if (args.json) {
947
1045
  console.log(JSON.stringify(result, null, 2));
948
1046
  }
1047
+ else if (isTruthyFlag(args.summary)) {
1048
+ printWorkspaceSummary(report);
1049
+ }
949
1050
  else {
950
1051
  printWorkspaceLifecycle(report);
951
1052
  }
@@ -960,6 +1061,7 @@ const workspaceCleanup = defineCommand({
960
1061
  'dry-run': { type: 'boolean', default: false, description: 'Preview cleanup; this is the default unless --apply is set' },
961
1062
  apply: { type: 'boolean', default: false, description: 'Actually run git worktree remove after safety checks' },
962
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' },
963
1065
  json: { type: 'boolean', default: false },
964
1066
  },
965
1067
  async run({ args }) {
@@ -971,6 +1073,14 @@ const workspaceCleanup = defineCommand({
971
1073
  if (args.json) {
972
1074
  console.log(JSON.stringify(result, null, 2));
973
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
+ }
974
1084
  else {
975
1085
  printWorkspaceCleanup(result);
976
1086
  }
@@ -1022,6 +1132,9 @@ const preflight = defineCommand({
1022
1132
  profile: args.profile,
1023
1133
  service: args.service,
1024
1134
  });
1135
+ const engineeringStandards = evaluateEngineeringStandardsGate({
1136
+ policy: resolved.policy,
1137
+ });
1025
1138
  const targetResults = [];
1026
1139
  if (!args.json) {
1027
1140
  console.log('\nSCALE Preflight');
@@ -1030,6 +1143,13 @@ const preflight = defineCommand({
1030
1143
  console.log(` Profile: ${resolved.profileName}`);
1031
1144
  console.log(` Preflight profile: ${preflightProfile}`);
1032
1145
  console.log(` Gates: ${gateStages.join(', ')}`);
1146
+ if (engineeringStandards.checked) {
1147
+ const status = engineeringStandards.blocked ? 'BLOCKED' : engineeringStandards.ok ? 'OK' : 'WARN';
1148
+ console.log(` Engineering standards: ${status} (${engineeringStandards.mode})`);
1149
+ }
1150
+ else {
1151
+ console.log(' Engineering standards: skipped');
1152
+ }
1033
1153
  }
1034
1154
  for (const target of resolved.targets) {
1035
1155
  if (!args.json) {
@@ -1061,7 +1181,9 @@ const preflight = defineCommand({
1061
1181
  }
1062
1182
  }
1063
1183
  }
1064
- const passed = targetResults.length > 0 && targetResults.every(target => target.passed);
1184
+ const passed = targetResults.length > 0 &&
1185
+ targetResults.every(target => target.passed) &&
1186
+ !engineeringStandards.blocked;
1065
1187
  const result = {
1066
1188
  phase: 'PREFLIGHT',
1067
1189
  profile: resolved.profileName,
@@ -1069,6 +1191,7 @@ const preflight = defineCommand({
1069
1191
  gates: gateStages,
1070
1192
  services: targetResults.map(target => target.service).filter(Boolean),
1071
1193
  policy: resolved.policy,
1194
+ engineeringStandards,
1072
1195
  targets: targetResults,
1073
1196
  passed,
1074
1197
  };
@@ -1207,7 +1330,7 @@ const init = defineCommand({
1207
1330
  'governance-pack': {
1208
1331
  type: 'string',
1209
1332
  default: 'standard',
1210
- description: 'Governance template pack (standard/project-scaffold/moe-workspace/go-service-matrix/node-library/frontend-app)',
1333
+ description: 'Governance template pack (standard/project-scaffold/moe-workspace/resource-governance/go-service-matrix/node-library/frontend-app)',
1211
1334
  },
1212
1335
  quick: { type: 'boolean', default: false, description: 'Quick start with auto-detection' },
1213
1336
  interactive: { type: 'boolean', default: false, description: 'Interactive configuration mode with prompts' },
@@ -1414,6 +1537,259 @@ const governance = defineCommand({
1414
1537
  subCommands: { diff: governanceDiff },
1415
1538
  });
1416
1539
  // ============================================================================
1540
+ // assets command - Resource lifecycle governance
1541
+ // ============================================================================
1542
+ const assetsScan = defineCommand({
1543
+ meta: { name: 'scan', description: 'Classify project docs, reports, media, scripts, and temporary outputs' },
1544
+ args: {
1545
+ dir: { type: 'string', default: '.', description: 'Project directory' },
1546
+ json: { type: 'boolean', default: false, description: 'Print JSON output' },
1547
+ },
1548
+ run({ args }) {
1549
+ const report = scanResourceAssets({ projectDir: args.dir });
1550
+ if (args.json) {
1551
+ console.log(JSON.stringify(report, null, 2));
1552
+ return;
1553
+ }
1554
+ console.log('SCALE Asset Scan');
1555
+ console.log(` Project: ${report.projectDir}`);
1556
+ console.log(` Total resources: ${report.summary.total}`);
1557
+ console.log(` Tracked forbidden: ${report.summary.trackedForbidden}`);
1558
+ console.log(` Large tracked: ${report.summary.largeTracked}`);
1559
+ console.log(` Expired: ${report.summary.expired}`);
1560
+ console.log('\nBy type:');
1561
+ for (const [type, count] of Object.entries(report.summary.byType)) {
1562
+ if (count > 0)
1563
+ console.log(` ${type}: ${count}`);
1564
+ }
1565
+ },
1566
+ });
1567
+ const assetsDoctor = defineCommand({
1568
+ meta: { name: 'doctor', description: 'Find resource lifecycle and Git policy problems' },
1569
+ args: {
1570
+ dir: { type: 'string', default: '.', description: 'Project directory' },
1571
+ json: { type: 'boolean', default: false, description: 'Print JSON output' },
1572
+ },
1573
+ run({ args }) {
1574
+ const report = doctorResourceAssets({ projectDir: args.dir });
1575
+ if (args.json) {
1576
+ console.log(JSON.stringify(report, null, 2));
1577
+ return;
1578
+ }
1579
+ console.log(`SCALE Asset Doctor: ${report.ok ? 'OK' : 'FAILED'}`);
1580
+ if (report.findings.length === 0) {
1581
+ console.log(' No resource lifecycle findings.');
1582
+ return;
1583
+ }
1584
+ for (const finding of report.findings) {
1585
+ const path = finding.path ? ` ${finding.path}` : '';
1586
+ console.log(` [${finding.severity.toUpperCase()}] ${finding.code}${path}: ${finding.message}`);
1587
+ if (finding.fix)
1588
+ console.log(` fix: ${finding.fix}`);
1589
+ }
1590
+ if (!report.ok)
1591
+ process.exitCode = 1;
1592
+ },
1593
+ });
1594
+ const assetsSettle = defineCommand({
1595
+ meta: { name: 'settle', description: 'Record resource lifecycle settlement evidence for a task' },
1596
+ args: {
1597
+ dir: { type: 'string', default: '.', description: 'Project directory' },
1598
+ 'task-id': { type: 'string', description: 'Task id for the settlement record' },
1599
+ 'artifact-dir': { type: 'string', description: 'Task artifact directory where resource-impact.md should be updated' },
1600
+ json: { type: 'boolean', default: false, description: 'Print JSON output' },
1601
+ },
1602
+ run({ args }) {
1603
+ const report = settleResourceAssets({
1604
+ projectDir: args.dir,
1605
+ taskId: args['task-id'],
1606
+ artifactsDir: args['artifact-dir'],
1607
+ });
1608
+ if (args.json) {
1609
+ console.log(JSON.stringify(report, null, 2));
1610
+ }
1611
+ else {
1612
+ console.log(`SCALE Asset Settlement: ${report.ok ? 'OK' : 'FAILED'}`);
1613
+ if (report.resourceImpactPath)
1614
+ console.log(` Resource impact: ${report.resourceImpactPath}`);
1615
+ if (report.doctor.findings.length > 0) {
1616
+ for (const finding of report.doctor.findings) {
1617
+ const path = finding.path ? ` ${finding.path}` : '';
1618
+ console.log(` [${finding.severity.toUpperCase()}] ${finding.code}${path}: ${finding.message}`);
1619
+ }
1620
+ }
1621
+ }
1622
+ if (!report.ok)
1623
+ process.exitCode = 1;
1624
+ },
1625
+ });
1626
+ const assets = defineCommand({
1627
+ meta: { name: 'assets', description: 'Resource lifecycle governance for generated and maintained project assets' },
1628
+ subCommands: { scan: assetsScan, doctor: assetsDoctor, settle: assetsSettle },
1629
+ });
1630
+ // ============================================================================
1631
+ // standards command - Engineering standards governance
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
+ }
1665
+ const standardsScan = defineCommand({
1666
+ meta: { name: 'scan', description: 'Scan source files for engineering standard violations' },
1667
+ args: {
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' },
1671
+ json: { type: 'boolean', default: false, description: 'Print JSON output' },
1672
+ },
1673
+ run({ args }) {
1674
+ const report = scanEngineeringStandards({ projectDir: args.dir, changedFiles: resolveChangedFilesArg(args) });
1675
+ if (args.json) {
1676
+ console.log(JSON.stringify(report, null, 2));
1677
+ return;
1678
+ }
1679
+ console.log('SCALE Standards Scan');
1680
+ console.log(` Project: ${report.projectDir}`);
1681
+ console.log(` Files scanned: ${report.summary.filesScanned}`);
1682
+ console.log(` Findings: ${report.summary.totalFindings}`);
1683
+ console.log(` Blocking findings: ${report.summary.blockingFindings}`);
1684
+ for (const finding of report.findings.slice(0, 20)) {
1685
+ const line = finding.line ? `:${finding.line}` : '';
1686
+ console.log(` [${finding.severity.toUpperCase()}] ${finding.ruleId} ${finding.path}${line}: ${finding.message}`);
1687
+ }
1688
+ if (report.findings.length > 20)
1689
+ console.log(` ... ${report.findings.length - 20} more finding(s)`);
1690
+ },
1691
+ });
1692
+ const standardsDoctor = defineCommand({
1693
+ meta: { name: 'doctor', description: 'Find blocking engineering standards problems' },
1694
+ args: {
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' },
1698
+ json: { type: 'boolean', default: false, description: 'Print JSON output' },
1699
+ },
1700
+ run({ args }) {
1701
+ const report = doctorEngineeringStandards({ projectDir: args.dir, changedFiles: resolveChangedFilesArg(args) });
1702
+ if (args.json) {
1703
+ console.log(JSON.stringify(report, null, 2));
1704
+ if (!report.ok)
1705
+ process.exitCode = 1;
1706
+ return;
1707
+ }
1708
+ console.log(`SCALE Standards Doctor: ${report.ok ? 'OK' : 'FAILED'}`);
1709
+ if (report.findings.length === 0) {
1710
+ console.log(' No engineering standards findings.');
1711
+ return;
1712
+ }
1713
+ for (const finding of report.findings) {
1714
+ const line = finding.line ? `:${finding.line}` : '';
1715
+ console.log(` [${finding.severity.toUpperCase()}] ${finding.ruleId} ${finding.path}${line}: ${finding.message}`);
1716
+ if (finding.fix)
1717
+ console.log(` fix: ${finding.fix}`);
1718
+ }
1719
+ if (!report.ok)
1720
+ process.exitCode = 1;
1721
+ },
1722
+ });
1723
+ const standardsSettle = defineCommand({
1724
+ meta: { name: 'settle', description: 'Record engineering standards settlement evidence for a task' },
1725
+ args: {
1726
+ dir: { type: 'string', default: '.', description: 'Project directory' },
1727
+ 'task-id': { type: 'string', description: 'Task id for the settlement record' },
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' },
1731
+ json: { type: 'boolean', default: false, description: 'Print JSON output' },
1732
+ },
1733
+ run({ args }) {
1734
+ const report = settleEngineeringStandards({
1735
+ projectDir: args.dir,
1736
+ taskId: args['task-id'],
1737
+ artifactsDir: args['artifact-dir'],
1738
+ changedFiles: resolveChangedFilesArg(args),
1739
+ });
1740
+ if (args.json) {
1741
+ console.log(JSON.stringify(report, null, 2));
1742
+ }
1743
+ else {
1744
+ console.log(`SCALE Standards Settlement: ${report.ok ? 'OK' : 'FAILED'}`);
1745
+ if (report.standardsImpactPath)
1746
+ console.log(` Standards impact: ${report.standardsImpactPath}`);
1747
+ for (const finding of report.doctor.findings) {
1748
+ const line = finding.line ? `:${finding.line}` : '';
1749
+ console.log(` [${finding.severity.toUpperCase()}] ${finding.ruleId} ${finding.path}${line}: ${finding.message}`);
1750
+ }
1751
+ }
1752
+ if (!report.ok)
1753
+ process.exitCode = 1;
1754
+ },
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
+ });
1788
+ const standards = defineCommand({
1789
+ meta: { name: 'standards', description: 'Engineering standards governance for logs, security, architecture, database, and code quality' },
1790
+ subCommands: { scan: standardsScan, doctor: standardsDoctor, settle: standardsSettle, baseline: standardsBaseline },
1791
+ });
1792
+ // ============================================================================
1417
1793
  // evolve command
1418
1794
  // ============================================================================
1419
1795
  const evolve = defineCommand({
@@ -1849,9 +2225,331 @@ const skillCheckCommand = defineCommand({
1849
2225
  process.exitCode = 1;
1850
2226
  },
1851
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
+ });
1852
2305
  const skill = defineCommand({
1853
2306
  meta: { name: 'skill', description: 'Skill discovery and management' },
1854
- subCommands: { scan: skillScan, doctor: skillDoctorCommand, plan: skillPlanCommand, check: skillCheckCommand },
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 },
1855
2553
  });
1856
2554
  // ============================================================================
1857
2555
  // agent commands — Multi-Agent 协作系统 (Phase 9)
@@ -1908,9 +2606,32 @@ const agentProfiles = defineCommand({
1908
2606
  }
1909
2607
  },
1910
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
+ });
1911
2632
  const agent = defineCommand({
1912
2633
  meta: { name: 'agent', description: 'Multi-Agent system management' },
1913
- subCommands: { spawn: agentSpawn, list: agentList, profiles: agentProfiles },
2634
+ subCommands: { spawn: agentSpawn, list: agentList, profiles: agentProfiles, leaders: agentLeaders },
1914
2635
  });
1915
2636
  // ============================================================================
1916
2637
  // team commands — 团队协作 (Phase 9)
@@ -1976,7 +2697,7 @@ import * as phaseCommands from '../cli/phaseCommands.js';
1976
2697
  import * as liteCommands from '../cli/liteCommands.js';
1977
2698
  import * as vibeCommands from '../cli/vibeCommands.js';
1978
2699
  const main = defineCommand({
1979
- meta: { name: 'scale', version: '0.13.0', description: 'SCALE Engine v0.13.0 CLI - hardened phase workflow gates, governance templates, platform adapters, skill routing, and verification automation' },
2700
+ meta: { name: 'scale', version: SCALE_ENGINE_VERSION, description: `SCALE Engine v${SCALE_ENGINE_VERSION} CLI - hardened phase workflow gates, governance templates, platform adapters, skill routing, and verification automation` },
1980
2701
  subCommands: {
1981
2702
  // Lite Mode (agent-skills style interactive entry)
1982
2703
  lite: liteCommands.liteCommand,
@@ -2008,12 +2729,15 @@ const main = defineCommand({
2008
2729
  stats,
2009
2730
  preflight,
2010
2731
  governance,
2732
+ assets,
2733
+ standards,
2011
2734
  metrics,
2012
2735
  'task-artifacts': taskArtifacts,
2013
2736
  workspace,
2014
2737
  status,
2015
2738
  workflow,
2016
2739
  evidence,
2740
+ tool,
2017
2741
  skill,
2018
2742
  skills: skill,
2019
2743
  agent,