@hongmaple0820/scale-engine 0.21.2 → 0.24.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 (135) hide show
  1. package/README.en.md +35 -11
  2. package/README.md +54 -23
  3. package/dist/api/cli.js +476 -5
  4. package/dist/api/cli.js.map +1 -1
  5. package/dist/api/doctor.d.ts +1 -0
  6. package/dist/api/doctor.js +83 -0
  7. package/dist/api/doctor.js.map +1 -1
  8. package/dist/artifact/types.d.ts +1 -1
  9. package/dist/artifact/types.js.map +1 -1
  10. package/dist/cli/phaseCommands.js +22 -6
  11. package/dist/cli/phaseCommands.js.map +1 -1
  12. package/dist/cli/runCommand.d.ts +39 -0
  13. package/dist/cli/runCommand.js +113 -0
  14. package/dist/cli/runCommand.js.map +1 -0
  15. package/dist/config/profiles.d.ts +52 -0
  16. package/dist/config/profiles.js +162 -0
  17. package/dist/config/profiles.js.map +1 -0
  18. package/dist/context/ContextBudget.d.ts +25 -1
  19. package/dist/context/ContextBudget.js +72 -7
  20. package/dist/context/ContextBudget.js.map +1 -1
  21. package/dist/context/ProjectAnatomy.d.ts +18 -0
  22. package/dist/context/ProjectAnatomy.js +287 -0
  23. package/dist/context/ProjectAnatomy.js.map +1 -0
  24. package/dist/dashboard/DashboardServer.d.ts +3 -0
  25. package/dist/dashboard/DashboardServer.js +114 -0
  26. package/dist/dashboard/DashboardServer.js.map +1 -1
  27. package/dist/dashboard/MetricsAggregator.d.ts +38 -0
  28. package/dist/dashboard/MetricsAggregator.js +99 -0
  29. package/dist/dashboard/MetricsAggregator.js.map +1 -0
  30. package/dist/dashboard/index.d.ts +2 -0
  31. package/dist/dashboard/index.js +1 -0
  32. package/dist/dashboard/index.js.map +1 -1
  33. package/dist/dashboard/server.js +1 -1
  34. package/dist/dashboard/server.js.map +1 -1
  35. package/dist/evolution/AutoDefectCreator.d.ts +11 -2
  36. package/dist/evolution/AutoDefectCreator.js +46 -2
  37. package/dist/evolution/AutoDefectCreator.js.map +1 -1
  38. package/dist/evolution/EvolutionEngine.d.ts +3 -0
  39. package/dist/evolution/EvolutionEngine.js +18 -2
  40. package/dist/evolution/EvolutionEngine.js.map +1 -1
  41. package/dist/evolution/RuleMaturity.d.ts +39 -0
  42. package/dist/evolution/RuleMaturity.js +70 -0
  43. package/dist/evolution/RuleMaturity.js.map +1 -0
  44. package/dist/guardrails/ActiveRedTeam.d.ts +46 -0
  45. package/dist/guardrails/ActiveRedTeam.js +203 -0
  46. package/dist/guardrails/ActiveRedTeam.js.map +1 -0
  47. package/dist/guardrails/DependencyAuditor.d.ts +68 -0
  48. package/dist/guardrails/DependencyAuditor.js +331 -0
  49. package/dist/guardrails/DependencyAuditor.js.map +1 -0
  50. package/dist/hooks/BugPatternDetector.d.ts +36 -0
  51. package/dist/hooks/BugPatternDetector.js +207 -0
  52. package/dist/hooks/BugPatternDetector.js.map +1 -0
  53. package/dist/hooks/HookGeneratorEnhanced.js +301 -5
  54. package/dist/hooks/HookGeneratorEnhanced.js.map +1 -1
  55. package/dist/hooks/WorkflowHooksManager.js +24 -0
  56. package/dist/hooks/WorkflowHooksManager.js.map +1 -1
  57. package/dist/index.d.ts +10 -0
  58. package/dist/index.js +7 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/knowledge/CerebrumManager.d.ts +25 -0
  61. package/dist/knowledge/CerebrumManager.js +127 -0
  62. package/dist/knowledge/CerebrumManager.js.map +1 -0
  63. package/dist/knowledge/SQLiteKnowledgeBase.d.ts +1 -0
  64. package/dist/knowledge/SQLiteKnowledgeBase.js +31 -3
  65. package/dist/knowledge/SQLiteKnowledgeBase.js.map +1 -1
  66. package/dist/knowledge/TfidfIndex.d.ts +50 -0
  67. package/dist/knowledge/TfidfIndex.js +177 -0
  68. package/dist/knowledge/TfidfIndex.js.map +1 -0
  69. package/dist/output/GovernanceDashboard.d.ts +2 -0
  70. package/dist/output/GovernanceDashboard.js +31 -0
  71. package/dist/output/GovernanceDashboard.js.map +1 -1
  72. package/dist/routing/PromptCachePolicy.d.ts +37 -0
  73. package/dist/routing/PromptCachePolicy.js +97 -0
  74. package/dist/routing/PromptCachePolicy.js.map +1 -0
  75. package/dist/runtime/ModelUsageLedger.d.ts +50 -0
  76. package/dist/runtime/ModelUsageLedger.js +92 -0
  77. package/dist/runtime/ModelUsageLedger.js.map +1 -0
  78. package/dist/runtime/index.d.ts +1 -0
  79. package/dist/runtime/index.js +1 -0
  80. package/dist/runtime/index.js.map +1 -1
  81. package/dist/skills/SkillDiscovery.js +1 -1
  82. package/dist/skills/SkillDiscovery.js.map +1 -1
  83. package/dist/tools/CommandOutputCompressor.d.ts +28 -0
  84. package/dist/tools/CommandOutputCompressor.js +242 -0
  85. package/dist/tools/CommandOutputCompressor.js.map +1 -0
  86. package/dist/tools/CommandRunLedger.d.ts +77 -0
  87. package/dist/tools/CommandRunLedger.js +111 -0
  88. package/dist/tools/CommandRunLedger.js.map +1 -0
  89. package/dist/tools/index.d.ts +2 -0
  90. package/dist/tools/index.js +2 -0
  91. package/dist/tools/index.js.map +1 -1
  92. package/dist/workflow/EngineeringStandards.js +91 -2
  93. package/dist/workflow/EngineeringStandards.js.map +1 -1
  94. package/dist/workflow/GovernanceTemplatePacks.js +2 -2
  95. package/dist/workflow/GovernanceTemplates.js +93 -92
  96. package/dist/workflow/GovernanceTemplates.js.map +1 -1
  97. package/dist/workflow/TaskLevelDetector.d.ts +41 -0
  98. package/dist/workflow/TaskLevelDetector.js +219 -0
  99. package/dist/workflow/TaskLevelDetector.js.map +1 -0
  100. package/dist/workflow/WorkflowOrchestrator.d.ts +59 -0
  101. package/dist/workflow/WorkflowOrchestrator.js +326 -0
  102. package/dist/workflow/WorkflowOrchestrator.js.map +1 -0
  103. package/dist/workflow/autonomous/BackgroundHunter.d.ts +74 -0
  104. package/dist/workflow/autonomous/BackgroundHunter.js +220 -0
  105. package/dist/workflow/autonomous/BackgroundHunter.js.map +1 -0
  106. package/dist/workflow/autonomous/index.d.ts +1 -0
  107. package/dist/workflow/autonomous/index.js +1 -0
  108. package/dist/workflow/autonomous/index.js.map +1 -1
  109. package/dist/workflow/gates/GateSystem.d.ts +33 -6
  110. package/dist/workflow/gates/GateSystem.js +176 -25
  111. package/dist/workflow/gates/GateSystem.js.map +1 -1
  112. package/dist/workflow/gates/MetaGovernanceGates.d.ts +70 -0
  113. package/dist/workflow/gates/MetaGovernanceGates.js +617 -0
  114. package/dist/workflow/gates/MetaGovernanceGates.js.map +1 -0
  115. package/dist/workflow/gates/VisualGate.d.ts +41 -0
  116. package/dist/workflow/gates/VisualGate.js +174 -0
  117. package/dist/workflow/gates/VisualGate.js.map +1 -0
  118. package/dist/workflow/index.d.ts +1 -0
  119. package/dist/workflow/index.js +1 -0
  120. package/dist/workflow/index.js.map +1 -1
  121. package/dist/workflow/types.d.ts +6 -1
  122. package/docs/ACTIVE_SECURITY_VISUAL_GATES.md +87 -0
  123. package/docs/BACKGROUND_HUNTER.md +62 -0
  124. package/docs/CONTEXT_BUDGET.md +32 -6
  125. package/docs/DEPENDENCY_AUDIT.md +89 -0
  126. package/docs/EVOLUTION_SHADOW_MODE.md +63 -0
  127. package/docs/GOVERNANCE_DASHBOARD.md +21 -5
  128. package/docs/README.md +24 -12
  129. package/docs/start/README.md +29 -3
  130. package/docs/start/artifact-lifecycle.md +326 -0
  131. package/docs/start/workflow-upgrade.md +150 -0
  132. package/image/wechat-public.jpg +0 -0
  133. package/image/wxPay.jpg +0 -0
  134. package/image/zfb.jpg +0 -0
  135. package/package.json +7 -2
package/dist/api/cli.js CHANGED
@@ -9,9 +9,13 @@ import { registerAllFSMs, INITIAL_STATES } from '../artifact/fsmDefinitions.js';
9
9
  import { Gateway } from '../guardrails/Gateway.js';
10
10
  import { BruteRetryDetector, PrematureDoneDetector, BlameShiftDetector } from '../guardrails/detectors.js';
11
11
  import { DangerousCommandDetector, SecretLeakDetector, RoleGateDetector, ScopeCreepDetector, BUILT_IN_ROLES } from '../guardrails/advancedDetectors.js';
12
+ import { auditDependencies } from '../guardrails/DependencyAuditor.js';
12
13
  import { SQLiteKnowledgeBase } from '../knowledge/SQLiteKnowledgeBase.js';
13
14
  import { ContextBuilder } from '../context/ContextBuilder.js';
15
+ import { ProjectAnatomy } from '../context/ProjectAnatomy.js';
14
16
  import { buildContextPack, doctorContextBudget, scanContextBudget, writeContextBudgetReport, } from '../context/ContextBudget.js';
17
+ import { resolvePromptCachePolicy } from '../routing/PromptCachePolicy.js';
18
+ import { CerebrumManager } from '../knowledge/CerebrumManager.js';
15
19
  import { buildCodeGraphContext, createCodeGraphRoiReport, impactCodeGraph, inspectCodeIntelligence, queryCodeGraph, writeCodeIntelligenceConfig, } from '../codegraph/CodeIntelligence.js';
16
20
  import { WorkflowEvalStore, compareWorkflowEvalRuns, renderWorkflowEvalReport, runWorkflowEvalSuite, } from '../eval/WorkflowEval.js';
17
21
  import { FSMAgentBridge } from '../fsm/FSMAgentBridge.js';
@@ -36,6 +40,7 @@ import { ReviewStore } from '../workflow/ReviewStore.js';
36
40
  import { WorkflowEngine } from '../workflow/WorkflowEngine.js';
37
41
  import { resolveVerificationTargets, } from '../workflow/VerificationProfile.js';
38
42
  import { writeGovernanceTemplates } from '../workflow/GovernanceTemplates.js';
43
+ import { getProfile as getConfigProfile, generateConfigForProfile, listProfiles as listConfigProfiles } from '../config/profiles.js';
39
44
  import { computeGovernanceDrift } from '../workflow/GovernanceLock.js';
40
45
  import { applyUpgradePlan, createThirdPartyUpdateReport, createUpgradeCheckReport, createUpgradePlanReport, rollbackLatestUpgrade, writeUpgradePlanHtml, } from '../workflow/UpgradeManager.js';
41
46
  import { createGovernanceRoiReport } from '../governance/GovernanceRoi.js';
@@ -44,6 +49,7 @@ import { baselineEngineeringStandards, doctorEngineeringStandards, scanEngineeri
44
49
  import { doctorResourceAssets, scanResourceAssets, settleResourceAssets } from '../workflow/ResourceGovernance.js';
45
50
  import { analyzeContextGovernance, renderContextGrillPrompt, writeContextGovernanceTemplates, } from '../workflow/ContextGovernance.js';
46
51
  import { createDiagnosticLoop, renderDiagnosticLoopMarkdown, validateDiagnosticLoop, } from '../workflow/DiagnosticLoop.js';
52
+ import { BackgroundHunter, HuntFindingStore } from '../workflow/autonomous/BackgroundHunter.js';
47
53
  import { createTddSlice, evaluateTddSlice, renderTddSliceMarkdown, } from '../workflow/TddLoop.js';
48
54
  import { nextWorkflowOpenTask, removeWorkflowOpenTask, toolEvidenceRunCompletesOpenTask } from '../workflow/WorkflowOpenTasks.js';
49
55
  import { TaskMetricsStore } from '../workflow/TaskMetricsStore.js';
@@ -79,6 +85,19 @@ function governanceModeFromScenario(scenario) {
79
85
  return 'minimal';
80
86
  return 'standard';
81
87
  }
88
+ function profileFromScenario(scenario) {
89
+ if (scenario === 'sandbox')
90
+ return 'minimal';
91
+ if (scenario === 'critical')
92
+ return 'advanced';
93
+ return 'standard';
94
+ }
95
+ function writeConfigYaml(projectDir, profileId, projectName, agents) {
96
+ const configPath = join(projectDir, '.scale', 'config.yaml');
97
+ const content = generateConfigForProfile(profileId, { name: projectName, agents });
98
+ writeFileSync(configPath, content, 'utf-8');
99
+ return configPath;
100
+ }
82
101
  function ensureDir(dir) {
83
102
  if (!existsSync(dir))
84
103
  mkdirSync(dir, { recursive: true });
@@ -346,6 +365,60 @@ const gate = defineCommand({
346
365
  subCommands: { 'pre-tool': gatePreTool, 'post-tool': gatePostTool, 'before-stop': gateBeforeStop },
347
366
  });
348
367
  // ============================================================================
368
+ // meta-governance — 元治理门禁 (G9-G15)
369
+ // ============================================================================
370
+ const metaGovernance = defineCommand({
371
+ meta: { name: 'meta-governance', description: 'Run meta-governance gates (G9-G15) — check if governance capabilities are actually used' },
372
+ args: {
373
+ 'scale-dir': { type: 'string', default: '.scale' },
374
+ json: { type: 'boolean', default: false, description: 'Output as JSON' },
375
+ },
376
+ async run({ args }) {
377
+ const { eventBus } = getEngine();
378
+ const { GateSystem } = await import('../workflow/gates/GateSystem.js');
379
+ const gateSystem = new GateSystem(eventBus);
380
+ const results = await gateSystem.executeMetaGovernance(args['scale-dir']);
381
+ if (args.json) {
382
+ console.log(JSON.stringify(results, null, 2));
383
+ return;
384
+ }
385
+ const stageNames = {
386
+ G9: 'Knowledge Utilization',
387
+ G10: 'Evolution Effectiveness',
388
+ G11: 'Guardrail Effectiveness',
389
+ G12: 'Workflow Thoroughness',
390
+ G13: 'Multi-Agent Coordination',
391
+ G14: 'Skill Utilization',
392
+ G15: 'Self-Improvement',
393
+ };
394
+ let allPassed = true;
395
+ for (const result of results) {
396
+ const icon = result.passed ? '✅' : '❌';
397
+ const name = stageNames[result.gate] ?? result.gate;
398
+ console.log(`${icon} ${result.gate} ${name}`);
399
+ if (result.evidence) {
400
+ for (const line of result.evidence.split('\n')) {
401
+ console.log(` ${line}`);
402
+ }
403
+ }
404
+ if (!result.passed) {
405
+ allPassed = false;
406
+ for (const blocker of result.blockers) {
407
+ console.log(` ⛔ ${blocker}`);
408
+ }
409
+ }
410
+ console.log();
411
+ }
412
+ if (!allPassed) {
413
+ console.log('❌ Meta-governance check FAILED — some capabilities are not being effectively used');
414
+ process.exit(1);
415
+ }
416
+ else {
417
+ console.log('✅ All meta-governance gates passed');
418
+ }
419
+ },
420
+ });
421
+ // ============================================================================
349
422
  // artifact CRUD
350
423
  // ============================================================================
351
424
  const create = defineCommand({
@@ -942,6 +1015,7 @@ const contextBudget = defineCommand({
942
1015
  dir: { type: 'string', default: PROJECT_DIR, description: 'Project directory' },
943
1016
  'max-always': { type: 'string', description: 'Maximum Always-loaded estimated tokens' },
944
1017
  'max-task': { type: 'string', description: 'Maximum task context estimated tokens' },
1018
+ provider: { type: 'string', default: 'generic', description: 'Model provider for prompt cache policy: anthropic, openai, or generic' },
945
1019
  write: { type: 'boolean', default: false, description: 'Write .scale/context-budget.json' },
946
1020
  json: { type: 'boolean', default: false },
947
1021
  },
@@ -954,9 +1028,13 @@ const contextBudget = defineCommand({
954
1028
  maxAlwaysTokens: parsePositiveIntArg(args['max-always'], '--max-always'),
955
1029
  maxTaskTokens: parsePositiveIntArg(args['max-task'], '--max-task'),
956
1030
  });
1031
+ const promptCache = resolvePromptCachePolicy({
1032
+ provider: String(args.provider ?? 'generic'),
1033
+ entries: report.entries,
1034
+ });
957
1035
  const path = isTruthyFlag(args.write) ? writeContextBudgetReport(report) : undefined;
958
1036
  if (args.json) {
959
- console.log(JSON.stringify({ ...report, path }, null, 2));
1037
+ console.log(JSON.stringify({ ...report, promptCache, path }, null, 2));
960
1038
  return;
961
1039
  }
962
1040
  console.log('SCALE Context Budget');
@@ -966,6 +1044,9 @@ const contextBudget = defineCommand({
966
1044
  for (const [category, summary] of Object.entries(report.summary.byCategory)) {
967
1045
  console.log(` ${category}: ${summary.tokens} tokens in ${summary.files} files`);
968
1046
  }
1047
+ console.log(` Prompt cache provider: ${promptCache.provider}`);
1048
+ console.log(` Prompt cache strategy: ${promptCache.strategy}${promptCache.supported ? '' : ' (usage ledger only)'}`);
1049
+ console.log(` Cache eligible: ${promptCache.cacheEligibleTokens} tokens across ${promptCache.cacheEligiblePaths.length} paths`);
969
1050
  for (const recommendation of report.recommendations)
970
1051
  console.log(` recommendation: ${recommendation}`);
971
1052
  if (path)
@@ -1013,6 +1094,9 @@ const contextDoctor = defineCommand({
1013
1094
  dir: { type: 'string', default: PROJECT_DIR, description: 'Project directory' },
1014
1095
  'max-always': { type: 'string', description: 'Maximum Always-loaded estimated tokens' },
1015
1096
  'max-task': { type: 'string', description: 'Maximum task context estimated tokens' },
1097
+ task: { type: 'string', description: 'Task text for a representative lazy context pack probe' },
1098
+ level: { type: 'string', default: 'M', description: 'Task level for the context pack probe' },
1099
+ files: { type: 'string', description: 'Comma-separated scoped files for the context pack probe' },
1016
1100
  json: { type: 'boolean', default: false },
1017
1101
  },
1018
1102
  run({ args }) {
@@ -1023,6 +1107,9 @@ const contextDoctor = defineCommand({
1023
1107
  scaleDir,
1024
1108
  maxAlwaysTokens: parsePositiveIntArg(args['max-always'], '--max-always'),
1025
1109
  maxTaskTokens: parsePositiveIntArg(args['max-task'], '--max-task'),
1110
+ task: args.task ? String(args.task) : undefined,
1111
+ level: String(args.level ?? 'M'),
1112
+ files: parseCommaList(args.files),
1026
1113
  });
1027
1114
  if (args.json) {
1028
1115
  console.log(JSON.stringify(report, null, 2));
@@ -1038,9 +1125,55 @@ const contextDoctor = defineCommand({
1038
1125
  process.exitCode = 1;
1039
1126
  },
1040
1127
  });
1128
+ const contextAnatomy = defineCommand({
1129
+ meta: { name: 'anatomy', description: 'Scan the project and generate .scale/anatomy.md for file-map context' },
1130
+ args: {
1131
+ dir: { type: 'string', default: PROJECT_DIR, description: 'Project directory' },
1132
+ 'max-files': { type: 'string', description: 'Maximum files to include; defaults to 500' },
1133
+ exclude: { type: 'string', description: 'Comma-separated directory names to exclude' },
1134
+ write: { type: 'boolean', default: false, description: 'Write .scale/anatomy.md' },
1135
+ json: { type: 'boolean', default: false },
1136
+ },
1137
+ run({ args }) {
1138
+ const projectDir = resolve(String(args.dir ?? PROJECT_DIR));
1139
+ const scaleDir = resolveScaleDirForProject(projectDir);
1140
+ const maxFiles = parsePositiveIntArg(args['max-files'], '--max-files');
1141
+ const excludePatterns = parseCommaList(args.exclude);
1142
+ const anatomy = new ProjectAnatomy();
1143
+ const sections = anatomy.scan(projectDir, {
1144
+ maxFiles,
1145
+ excludePatterns: excludePatterns.length > 0 ? excludePatterns : undefined,
1146
+ });
1147
+ const content = anatomy.serialize(sections);
1148
+ const summary = [...sections.values()].reduce((acc, entries) => {
1149
+ acc.files += entries.length;
1150
+ acc.tokens += entries.reduce((sum, entry) => sum + entry.tokens, 0);
1151
+ return acc;
1152
+ }, { files: 0, tokens: 0 });
1153
+ const outputPath = join(scaleDir, 'anatomy.md');
1154
+ if (isTruthyFlag(args.write)) {
1155
+ ensureDir(scaleDir);
1156
+ writeFileSync(outputPath, content, 'utf-8');
1157
+ }
1158
+ if (args.json) {
1159
+ console.log(JSON.stringify({
1160
+ ok: true,
1161
+ projectDir,
1162
+ outputPath: isTruthyFlag(args.write) ? outputPath : undefined,
1163
+ summary,
1164
+ }, null, 2));
1165
+ return;
1166
+ }
1167
+ console.log('SCALE Project Anatomy');
1168
+ console.log(` Files: ${summary.files}`);
1169
+ console.log(` Estimated tokens: ${summary.tokens}`);
1170
+ if (isTruthyFlag(args.write))
1171
+ console.log(` Wrote: ${outputPath}`);
1172
+ },
1173
+ });
1041
1174
  const context = defineCommand({
1042
1175
  meta: { name: 'context', description: 'Context assembly' },
1043
- subCommands: { build: contextBuild, status: contextStatus, inject: contextInject, glossary: contextGlossary, init: contextInit, grill: contextGrill, budget: contextBudget, pack: contextPack, doctor: contextDoctor },
1176
+ subCommands: { build: contextBuild, status: contextStatus, inject: contextInject, glossary: contextGlossary, init: contextInit, grill: contextGrill, budget: contextBudget, pack: contextPack, doctor: contextDoctor, anatomy: contextAnatomy },
1044
1177
  });
1045
1178
  // ============================================================================
1046
1179
  // codegraph command - Adapter-first code intelligence
@@ -1539,6 +1672,184 @@ const diagnose = defineCommand({
1539
1672
  subCommands: { plan: diagnosePlanCommand },
1540
1673
  });
1541
1674
  // ============================================================================
1675
+ // hunt command - readonly proactive governance scan
1676
+ // ============================================================================
1677
+ function createBackgroundHunter(args) {
1678
+ return new BackgroundHunter({ projectDir: args.dir ? String(args.dir) : PROJECT_DIR });
1679
+ }
1680
+ const huntScanCommand = defineCommand({
1681
+ meta: { name: 'scan', description: 'Run a readonly proactive governance scan' },
1682
+ args: {
1683
+ dir: { type: 'string', default: PROJECT_DIR, description: 'Project directory' },
1684
+ changed: { type: 'boolean', default: false, description: 'Scan changed Git files only' },
1685
+ 'changed-files': { type: 'string', description: 'Comma or newline separated file list to scan' },
1686
+ json: { type: 'boolean', default: false },
1687
+ },
1688
+ run({ args }) {
1689
+ const report = createBackgroundHunter(args).scan({
1690
+ changedFiles: resolveChangedFilesArg(args),
1691
+ });
1692
+ if (args.json) {
1693
+ console.log(JSON.stringify(report, null, 2));
1694
+ return;
1695
+ }
1696
+ printHuntReport(report);
1697
+ },
1698
+ });
1699
+ const huntReportCommand = defineCommand({
1700
+ meta: { name: 'report', description: 'Print open and ignored hunt findings' },
1701
+ args: {
1702
+ dir: { type: 'string', default: PROJECT_DIR, description: 'Project directory' },
1703
+ changed: { type: 'boolean', default: false, description: 'Scan changed Git files only' },
1704
+ 'changed-files': { type: 'string', description: 'Comma or newline separated file list to scan' },
1705
+ json: { type: 'boolean', default: false },
1706
+ },
1707
+ run({ args }) {
1708
+ const report = createBackgroundHunter(args).scan({
1709
+ changedFiles: resolveChangedFilesArg(args),
1710
+ });
1711
+ if (args.json) {
1712
+ console.log(JSON.stringify(report, null, 2));
1713
+ return;
1714
+ }
1715
+ printHuntReport(report);
1716
+ },
1717
+ });
1718
+ const huntDiagnoseCommand = defineCommand({
1719
+ meta: { name: 'diagnose', description: 'Create a diagnostic loop from a hunt finding' },
1720
+ args: {
1721
+ id: { type: 'positional', required: true, description: 'Hunt finding id' },
1722
+ dir: { type: 'string', default: PROJECT_DIR, description: 'Project directory' },
1723
+ changed: { type: 'boolean', default: false, description: 'Scan changed Git files only' },
1724
+ 'changed-files': { type: 'string', description: 'Comma or newline separated file list to scan' },
1725
+ json: { type: 'boolean', default: false },
1726
+ },
1727
+ run({ args }) {
1728
+ const report = createBackgroundHunter(args).scan({
1729
+ changedFiles: resolveChangedFilesArg(args),
1730
+ });
1731
+ const finding = report.findings.find(item => item.id === String(args.id));
1732
+ if (!finding) {
1733
+ console.error(`Hunt finding not found: ${String(args.id)}`);
1734
+ process.exitCode = 1;
1735
+ return;
1736
+ }
1737
+ const loop = createDiagnosticLoop(finding.diagnosticInput);
1738
+ const validation = validateDiagnosticLoop(loop);
1739
+ if (args.json) {
1740
+ console.log(JSON.stringify({ finding, loop, validation }, null, 2));
1741
+ return;
1742
+ }
1743
+ console.log(renderDiagnosticLoopMarkdown(loop));
1744
+ if (!validation.ready) {
1745
+ console.log('\nBlockers:');
1746
+ for (const blocker of validation.blockers)
1747
+ console.log(` - ${blocker}`);
1748
+ }
1749
+ },
1750
+ });
1751
+ const huntIgnoreCommand = defineCommand({
1752
+ meta: { name: 'ignore', description: 'Ignore a stable hunt finding fingerprint' },
1753
+ args: {
1754
+ id: { type: 'positional', required: true, description: 'Hunt finding id' },
1755
+ reason: { type: 'string', description: 'Why this finding is accepted or deferred' },
1756
+ dir: { type: 'string', default: PROJECT_DIR, description: 'Project directory' },
1757
+ changed: { type: 'boolean', default: false, description: 'Scan changed Git files only' },
1758
+ 'changed-files': { type: 'string', description: 'Comma or newline separated file list to scan' },
1759
+ json: { type: 'boolean', default: false },
1760
+ },
1761
+ run({ args }) {
1762
+ const projectDir = args.dir ? String(args.dir) : PROJECT_DIR;
1763
+ const report = new BackgroundHunter({ projectDir }).scan({
1764
+ changedFiles: resolveChangedFilesArg(args),
1765
+ });
1766
+ const finding = report.findings.find(item => item.id === String(args.id));
1767
+ if (!finding) {
1768
+ console.error(`Hunt finding not found: ${String(args.id)}`);
1769
+ process.exitCode = 1;
1770
+ return;
1771
+ }
1772
+ const ignored = new HuntFindingStore({ projectDir }).ignore({
1773
+ id: finding.id,
1774
+ fingerprint: finding.fingerprint,
1775
+ reason: args.reason ? String(args.reason) : undefined,
1776
+ ignoredAt: new Date().toISOString(),
1777
+ });
1778
+ if (args.json) {
1779
+ console.log(JSON.stringify({ ignored }, null, 2));
1780
+ return;
1781
+ }
1782
+ console.log(`Ignored hunt finding: ${ignored.id}`);
1783
+ if (ignored.reason)
1784
+ console.log(` Reason: ${ignored.reason}`);
1785
+ },
1786
+ });
1787
+ const hunt = defineCommand({
1788
+ meta: { name: 'hunt', description: 'Readonly proactive governance scans' },
1789
+ subCommands: {
1790
+ scan: huntScanCommand,
1791
+ report: huntReportCommand,
1792
+ diagnose: huntDiagnoseCommand,
1793
+ ignore: huntIgnoreCommand,
1794
+ },
1795
+ });
1796
+ function printHuntReport(report) {
1797
+ console.log('SCALE Hunt Report');
1798
+ console.log(` Project: ${report.projectDir}`);
1799
+ console.log(` Open findings: ${report.summary.open}`);
1800
+ console.log(` Ignored findings: ${report.summary.ignored}`);
1801
+ console.log(` Blocking findings: ${report.summary.blocking}`);
1802
+ for (const finding of report.findings.slice(0, 20)) {
1803
+ const line = finding.line ? `:${finding.line}` : '';
1804
+ const status = finding.status === 'ignored' ? 'IGNORED' : finding.severity.toUpperCase();
1805
+ console.log(` [${status}] ${finding.id} ${finding.ruleId} ${finding.path ?? 'project'}${line}: ${finding.message}`);
1806
+ }
1807
+ if (report.findings.length > 20)
1808
+ console.log(` ... ${report.findings.length - 20} more finding(s)`);
1809
+ }
1810
+ // ============================================================================
1811
+ // dependency command - supply-chain security audit
1812
+ // ============================================================================
1813
+ const dependencyAuditCommand = defineCommand({
1814
+ meta: { name: 'audit', description: 'Audit lockfile-scoped dependency supply-chain risk' },
1815
+ args: {
1816
+ dir: { type: 'string', default: PROJECT_DIR, description: 'Project directory' },
1817
+ mode: { type: 'string', description: 'Audit mode: compatibility, strict, or offline' },
1818
+ 'changed-packages': { type: 'string', description: 'Comma-separated package names to audit instead of direct dependencies' },
1819
+ json: { type: 'boolean', default: false },
1820
+ },
1821
+ run({ args }) {
1822
+ const mode = args.mode === 'compatibility' || args.mode === 'strict' || args.mode === 'offline'
1823
+ ? args.mode
1824
+ : undefined;
1825
+ const report = auditDependencies({
1826
+ projectDir: args.dir ? String(args.dir) : PROJECT_DIR,
1827
+ mode,
1828
+ changedPackages: parseCommaList(args['changed-packages']),
1829
+ });
1830
+ if (args.json) {
1831
+ console.log(JSON.stringify(report, null, 2));
1832
+ }
1833
+ else {
1834
+ console.log(`SCALE Dependency Audit: ${report.ok ? 'OK' : 'FAILED'}`);
1835
+ console.log(` Packages audited: ${report.summary.packagesAudited}`);
1836
+ console.log(` Findings: ${report.summary.totalFindings}`);
1837
+ console.log(` Mode: ${report.mode}`);
1838
+ for (const finding of report.findings.slice(0, 20)) {
1839
+ console.log(` [${finding.severity}] ${finding.ruleId} ${finding.packageName}${finding.version ? `@${finding.version}` : ''}: ${finding.message}`);
1840
+ }
1841
+ if (report.findings.length > 20)
1842
+ console.log(` ... ${report.findings.length - 20} more finding(s)`);
1843
+ }
1844
+ if (!report.ok)
1845
+ process.exitCode = 1;
1846
+ },
1847
+ });
1848
+ const dependency = defineCommand({
1849
+ meta: { name: 'dependency', description: 'Supply-chain dependency governance' },
1850
+ subCommands: { audit: dependencyAuditCommand },
1851
+ });
1852
+ // ============================================================================
1542
1853
  // tdd command - vertical slice RED/GREEN/REFACTOR loop
1543
1854
  // ============================================================================
1544
1855
  const tddSliceCommand = defineCommand({
@@ -2230,6 +2541,7 @@ const init = defineCommand({
2230
2541
  },
2231
2542
  quick: { type: 'boolean', default: false, description: 'Quick start with auto-detection' },
2232
2543
  interactive: { type: 'boolean', default: false, description: 'Interactive configuration mode with prompts' },
2544
+ profile: { type: 'string', default: '', description: 'Configuration profile (minimal/standard/advanced). Auto-mapped from scenario if not specified' },
2233
2545
  'coverage-threshold': { type: 'string', default: '80', description: 'Coverage threshold (default 80%)' },
2234
2546
  'retry-threshold': { type: 'string', default: '3', description: 'Brute retry threshold (default 3)' },
2235
2547
  'block-severity': { type: 'string', default: 'CRITICAL', description: 'Block severity level (CRITICAL/HIGH/MEDIUM)' },
@@ -2292,7 +2604,11 @@ const init = defineCommand({
2292
2604
  });
2293
2605
  result.created.push(...governance.created);
2294
2606
  result.skipped.push(...governance.skipped);
2295
- console.log(`\n✅ SCALE Engine initialized for ${agentType} (interactive mode)`);
2607
+ // Generate config.yaml from profile
2608
+ const profileId = args.profile || profileFromScenario(scenarioMode);
2609
+ const configPath = writeConfigYaml(args.dir, profileId, projectName, [agentType]);
2610
+ result.created.push(configPath);
2611
+ console.log(`\n✅ SCALE Engine initialized for ${agentType} (interactive mode, profile: ${profileId})`);
2296
2612
  console.log(`\n📁 Created:`);
2297
2613
  for (const f of result.created)
2298
2614
  console.log(` + ${f}`);
@@ -2305,8 +2621,10 @@ const init = defineCommand({
2305
2621
  console.log(` Settings: ${result.settingsPath}`);
2306
2622
  console.log(` Knowledge: ${result.knowledgeDocPath}`);
2307
2623
  console.log(` Thresholds: ${thresholdsPath}`);
2624
+ console.log(` Config: ${configPath}`);
2308
2625
  console.log(` Data dir: ${result.scaleDir}`);
2309
2626
  console.log(` Scenario: ${scenarioMode}`);
2627
+ console.log(` Profile: ${profileId}`);
2310
2628
  console.log(`\n📋 Next steps:`);
2311
2629
  for (const step of governanceNextSteps())
2312
2630
  console.log(` → ${step}`);
@@ -2315,6 +2633,14 @@ const init = defineCommand({
2315
2633
  // One-click quick start mode
2316
2634
  if (!args.agent) {
2317
2635
  const qsResult = await quickStart(args.dir, { governancePack: args['governance-pack'] });
2636
+ // Generate config.yaml from profile
2637
+ if (qsResult.success) {
2638
+ const profileId = args.profile || profileFromScenario(args.scenario);
2639
+ const projectName = args.dir.split(/[/\\]/).pop() || 'Project';
2640
+ const detectedAgent = qsResult.platform ? [qsResult.platform] : [];
2641
+ const configPath = writeConfigYaml(args.dir, profileId, projectName, detectedAgent);
2642
+ qsResult.created.push(configPath);
2643
+ }
2318
2644
  if (args.json) {
2319
2645
  const detection = qsResult.success ? undefined : detectPlatform(args.dir);
2320
2646
  console.log(JSON.stringify({
@@ -2369,15 +2695,21 @@ const init = defineCommand({
2369
2695
  });
2370
2696
  result.created.push(...governance.created);
2371
2697
  result.skipped.push(...governance.skipped);
2698
+ // Generate config.yaml from profile
2699
+ const profileId = args.profile || profileFromScenario(args.scenario);
2700
+ const configPath = writeConfigYaml(args.dir, profileId, projectName, [args.agent]);
2701
+ result.created.push(configPath);
2372
2702
  if (args.json) {
2373
2703
  console.log(JSON.stringify({
2374
2704
  ok: true,
2375
2705
  mode: args.quick ? 'quick-agent' : 'manual',
2376
2706
  agent: args.agent,
2377
2707
  scenario: args.scenario,
2708
+ profile: profileId,
2378
2709
  governancePack: args['governance-pack'],
2379
2710
  settingsPath: result.settingsPath,
2380
2711
  knowledgeDocPath: result.knowledgeDocPath,
2712
+ configPath,
2381
2713
  scaleDir: result.scaleDir,
2382
2714
  created: result.created,
2383
2715
  skipped: result.skipped,
@@ -2385,7 +2717,7 @@ const init = defineCommand({
2385
2717
  }, null, 2));
2386
2718
  return;
2387
2719
  }
2388
- console.log(`\n✅ SCALE Engine initialized for ${args.agent} (scenario: ${args.scenario})`);
2720
+ console.log(`\n✅ SCALE Engine initialized for ${args.agent} (scenario: ${args.scenario}, profile: ${profileId})`);
2389
2721
  console.log(`\n📁 Created:`);
2390
2722
  for (const f of result.created)
2391
2723
  console.log(` + ${f}`);
@@ -2396,6 +2728,7 @@ const init = defineCommand({
2396
2728
  }
2397
2729
  console.log(`\n🔧 Settings: ${result.settingsPath}`);
2398
2730
  console.log(`\n📖 Knowledge: ${result.knowledgeDocPath}`);
2731
+ console.log(`\n📄 Config: ${configPath}`);
2399
2732
  console.log(`\n📂 Data dir: ${result.scaleDir}`);
2400
2733
  console.log(`\n📋 Next steps:`);
2401
2734
  for (const step of governanceNextSteps())
@@ -2403,8 +2736,70 @@ const init = defineCommand({
2403
2736
  },
2404
2737
  });
2405
2738
  // ============================================================================
2406
- // governance command — Generated governance asset tooling
2739
+ // config command — Configuration profile management
2407
2740
  // ============================================================================
2741
+ const configProfile = defineCommand({
2742
+ meta: { name: 'profile', description: 'View or switch configuration profile' },
2743
+ args: {
2744
+ set: { type: 'string', default: '', description: 'Switch to profile (minimal/standard/advanced)' },
2745
+ list: { type: 'boolean', default: false, description: 'List all available profiles' },
2746
+ json: { type: 'boolean', default: false, description: 'Output as JSON' },
2747
+ },
2748
+ async run({ args }) {
2749
+ if (args.list) {
2750
+ const profiles = listConfigProfiles();
2751
+ if (args.json) {
2752
+ console.log(JSON.stringify(profiles, null, 2));
2753
+ return;
2754
+ }
2755
+ console.log('\nAvailable profiles:\n');
2756
+ for (const p of profiles) {
2757
+ console.log(` ${p.id.padEnd(12)} ${p.name} — ${p.description}`);
2758
+ }
2759
+ console.log(`\nUse: scale config profile --set <id>`);
2760
+ return;
2761
+ }
2762
+ if (args.set) {
2763
+ const profile = getConfigProfile(args.set);
2764
+ if (profile.id !== args.set) {
2765
+ console.log(`\n⚠️ Profile "${args.set}" not found. Available: minimal, standard, advanced`);
2766
+ return;
2767
+ }
2768
+ // Update config.yaml
2769
+ const configPath = join('.scale', 'config.yaml');
2770
+ const projectName = process.cwd().split(/[/\\]/).pop() || 'Project';
2771
+ const content = generateConfigForProfile(args.set, { name: projectName });
2772
+ ensureDir('.scale');
2773
+ writeFileSync(configPath, content, 'utf-8');
2774
+ console.log(`\n✅ Profile switched to: ${profile.name}`);
2775
+ console.log(` ${profile.description}`);
2776
+ console.log(`\n📄 Config updated: ${configPath}`);
2777
+ return;
2778
+ }
2779
+ // Show current profile
2780
+ const configPath = join('.scale', 'config.yaml');
2781
+ if (!existsSync(configPath)) {
2782
+ console.log('\n⚠️ No config.yaml found. Run: scale init');
2783
+ return;
2784
+ }
2785
+ const content = readFileSync(configPath, 'utf-8');
2786
+ const match = content.match(/^profile:\s*(.+)$/m);
2787
+ const currentProfile = match?.[1]?.trim() || 'standard';
2788
+ const profile = getConfigProfile(currentProfile);
2789
+ if (args.json) {
2790
+ console.log(JSON.stringify({ profile: profile.id, name: profile.name, description: profile.description, sections: profile.sections }, null, 2));
2791
+ return;
2792
+ }
2793
+ console.log(`\nCurrent profile: ${profile.name} (${profile.id})`);
2794
+ console.log(` ${profile.description}`);
2795
+ console.log(`\nSections: ${profile.sections.join(', ')}`);
2796
+ console.log(`\nUse: scale config profile --set <id> to switch`);
2797
+ },
2798
+ });
2799
+ const config = defineCommand({
2800
+ meta: { name: 'config', description: 'Configuration management' },
2801
+ subCommands: { profile: configProfile },
2802
+ });
2408
2803
  const governanceDiff = defineCommand({
2409
2804
  meta: { name: 'diff', description: 'Check generated governance files for drift' },
2410
2805
  args: {
@@ -3612,6 +4007,75 @@ const memoryDoctor = defineCommand({
3612
4007
  process.exitCode = 1;
3613
4008
  },
3614
4009
  });
4010
+ const memoryCerebrum = defineCommand({
4011
+ meta: { name: 'cerebrum', description: 'Maintain .scale/cerebrum.md do-not-repeat rules and preferences' },
4012
+ args: {
4013
+ type: { type: 'string', description: 'Optional entry type: preference or do-not-repeat' },
4014
+ pattern: { type: 'string', description: 'Pattern for do-not-repeat entries' },
4015
+ description: { type: 'string', description: 'Entry description or preference text' },
4016
+ tags: { type: 'string', description: 'Comma-separated tags for preferences' },
4017
+ write: { type: 'boolean', default: false, description: 'Write .scale/cerebrum.md' },
4018
+ json: { type: 'boolean', default: false },
4019
+ },
4020
+ async run({ args }) {
4021
+ const { kb } = getEngine();
4022
+ const manager = new CerebrumManager(kb);
4023
+ const type = args.type ? String(args.type).toLowerCase() : '';
4024
+ let created;
4025
+ if (type) {
4026
+ if (type === 'do-not-repeat' || type === 'do_not_repeat' || type === 'dnr') {
4027
+ const pattern = String(args.pattern ?? '').trim();
4028
+ const description = String(args.description ?? '').trim();
4029
+ if (!pattern || !description) {
4030
+ console.error('memory cerebrum --type do-not-repeat requires --pattern and --description.');
4031
+ process.exit(1);
4032
+ return;
4033
+ }
4034
+ created = await manager.addDoNotRepeat(pattern, description);
4035
+ }
4036
+ else if (type === 'preference' || type === 'pref') {
4037
+ const description = String(args.description ?? args.pattern ?? '').trim();
4038
+ if (!description) {
4039
+ console.error('memory cerebrum --type preference requires --description.');
4040
+ process.exit(1);
4041
+ return;
4042
+ }
4043
+ created = await manager.addPreference(description, parseCommaList(args.tags));
4044
+ }
4045
+ else {
4046
+ console.error('memory cerebrum --type must be preference or do-not-repeat.');
4047
+ process.exit(1);
4048
+ return;
4049
+ }
4050
+ }
4051
+ const entries = await manager.loadAll();
4052
+ const outputPath = join(SCALE_DIR, 'cerebrum.md');
4053
+ const shouldWrite = isTruthyFlag(args.write) || Boolean(created);
4054
+ if (shouldWrite) {
4055
+ ensureDir(SCALE_DIR);
4056
+ writeFileSync(outputPath, manager.toMarkdown(), 'utf-8');
4057
+ }
4058
+ const summary = {
4059
+ total: entries.length,
4060
+ doNotRepeat: entries.filter(entry => entry.type === 'do_not_repeat').length,
4061
+ preferences: entries.filter(entry => entry.type === 'preference').length,
4062
+ };
4063
+ if (args.json) {
4064
+ console.log(JSON.stringify({
4065
+ ok: true,
4066
+ outputPath: shouldWrite ? outputPath : undefined,
4067
+ created,
4068
+ summary,
4069
+ }, null, 2));
4070
+ return;
4071
+ }
4072
+ console.log('SCALE Cerebrum');
4073
+ console.log(` Do-not-repeat: ${summary.doNotRepeat}`);
4074
+ console.log(` Preferences: ${summary.preferences}`);
4075
+ if (shouldWrite)
4076
+ console.log(` Wrote: ${outputPath}`);
4077
+ },
4078
+ });
3615
4079
  const memorySettle = defineCommand({
3616
4080
  meta: { name: 'settle', description: 'Settle runtime evidence into a reviewable memory learning candidate' },
3617
4081
  args: {
@@ -3876,6 +4340,7 @@ const memory = defineCommand({
3876
4340
  subCommands: {
3877
4341
  pack: memoryPack,
3878
4342
  doctor: memoryDoctor,
4343
+ cerebrum: memoryCerebrum,
3879
4344
  settle: memorySettle,
3880
4345
  ingest: memoryIngest,
3881
4346
  query: memoryQuery,
@@ -4755,6 +5220,7 @@ const team = defineCommand({
4755
5220
  // Phase-Aligned Commands (v0.10.1) - agent-skills style
4756
5221
  // ============================================================================
4757
5222
  import * as phaseCommands from '../cli/phaseCommands.js';
5223
+ import { runCommand } from '../cli/runCommand.js';
4758
5224
  import * as liteCommands from '../cli/liteCommands.js';
4759
5225
  import * as vibeCommands from '../cli/vibeCommands.js';
4760
5226
  const main = defineCommand({
@@ -4773,11 +5239,13 @@ const main = defineCommand({
4773
5239
  verify: phaseCommands.phaseVerify,
4774
5240
  review: phaseCommands.phaseReview,
4775
5241
  ship: phaseCommands.phaseShip,
5242
+ run: runCommand,
4776
5243
  // Original commands (preserved)
4777
5244
  init,
4778
5245
  doctor,
4779
5246
  session,
4780
5247
  gate,
5248
+ 'meta-governance': metaGovernance,
4781
5249
  create,
4782
5250
  list,
4783
5251
  show,
@@ -4805,6 +5273,8 @@ const main = defineCommand({
4805
5273
  runtime,
4806
5274
  memory,
4807
5275
  diagnose,
5276
+ hunt,
5277
+ dependency,
4808
5278
  tdd,
4809
5279
  tool,
4810
5280
  tools: tool,
@@ -4814,6 +5284,7 @@ const main = defineCommand({
4814
5284
  team,
4815
5285
  'create-prd': createPRD,
4816
5286
  'out-of-scope': outOfScope,
5287
+ config,
4817
5288
  },
4818
5289
  });
4819
5290
  runMain(main);