@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.
- package/README.en.md +35 -11
- package/README.md +54 -23
- package/dist/api/cli.js +476 -5
- package/dist/api/cli.js.map +1 -1
- package/dist/api/doctor.d.ts +1 -0
- package/dist/api/doctor.js +83 -0
- package/dist/api/doctor.js.map +1 -1
- package/dist/artifact/types.d.ts +1 -1
- package/dist/artifact/types.js.map +1 -1
- package/dist/cli/phaseCommands.js +22 -6
- package/dist/cli/phaseCommands.js.map +1 -1
- package/dist/cli/runCommand.d.ts +39 -0
- package/dist/cli/runCommand.js +113 -0
- package/dist/cli/runCommand.js.map +1 -0
- package/dist/config/profiles.d.ts +52 -0
- package/dist/config/profiles.js +162 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/context/ContextBudget.d.ts +25 -1
- package/dist/context/ContextBudget.js +72 -7
- package/dist/context/ContextBudget.js.map +1 -1
- package/dist/context/ProjectAnatomy.d.ts +18 -0
- package/dist/context/ProjectAnatomy.js +287 -0
- package/dist/context/ProjectAnatomy.js.map +1 -0
- package/dist/dashboard/DashboardServer.d.ts +3 -0
- package/dist/dashboard/DashboardServer.js +114 -0
- package/dist/dashboard/DashboardServer.js.map +1 -1
- package/dist/dashboard/MetricsAggregator.d.ts +38 -0
- package/dist/dashboard/MetricsAggregator.js +99 -0
- package/dist/dashboard/MetricsAggregator.js.map +1 -0
- package/dist/dashboard/index.d.ts +2 -0
- package/dist/dashboard/index.js +1 -0
- package/dist/dashboard/index.js.map +1 -1
- package/dist/dashboard/server.js +1 -1
- package/dist/dashboard/server.js.map +1 -1
- package/dist/evolution/AutoDefectCreator.d.ts +11 -2
- package/dist/evolution/AutoDefectCreator.js +46 -2
- package/dist/evolution/AutoDefectCreator.js.map +1 -1
- package/dist/evolution/EvolutionEngine.d.ts +3 -0
- package/dist/evolution/EvolutionEngine.js +18 -2
- package/dist/evolution/EvolutionEngine.js.map +1 -1
- package/dist/evolution/RuleMaturity.d.ts +39 -0
- package/dist/evolution/RuleMaturity.js +70 -0
- package/dist/evolution/RuleMaturity.js.map +1 -0
- package/dist/guardrails/ActiveRedTeam.d.ts +46 -0
- package/dist/guardrails/ActiveRedTeam.js +203 -0
- package/dist/guardrails/ActiveRedTeam.js.map +1 -0
- package/dist/guardrails/DependencyAuditor.d.ts +68 -0
- package/dist/guardrails/DependencyAuditor.js +331 -0
- package/dist/guardrails/DependencyAuditor.js.map +1 -0
- package/dist/hooks/BugPatternDetector.d.ts +36 -0
- package/dist/hooks/BugPatternDetector.js +207 -0
- package/dist/hooks/BugPatternDetector.js.map +1 -0
- package/dist/hooks/HookGeneratorEnhanced.js +301 -5
- package/dist/hooks/HookGeneratorEnhanced.js.map +1 -1
- package/dist/hooks/WorkflowHooksManager.js +24 -0
- package/dist/hooks/WorkflowHooksManager.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/knowledge/CerebrumManager.d.ts +25 -0
- package/dist/knowledge/CerebrumManager.js +127 -0
- package/dist/knowledge/CerebrumManager.js.map +1 -0
- package/dist/knowledge/SQLiteKnowledgeBase.d.ts +1 -0
- package/dist/knowledge/SQLiteKnowledgeBase.js +31 -3
- package/dist/knowledge/SQLiteKnowledgeBase.js.map +1 -1
- package/dist/knowledge/TfidfIndex.d.ts +50 -0
- package/dist/knowledge/TfidfIndex.js +177 -0
- package/dist/knowledge/TfidfIndex.js.map +1 -0
- package/dist/output/GovernanceDashboard.d.ts +2 -0
- package/dist/output/GovernanceDashboard.js +31 -0
- package/dist/output/GovernanceDashboard.js.map +1 -1
- package/dist/routing/PromptCachePolicy.d.ts +37 -0
- package/dist/routing/PromptCachePolicy.js +97 -0
- package/dist/routing/PromptCachePolicy.js.map +1 -0
- package/dist/runtime/ModelUsageLedger.d.ts +50 -0
- package/dist/runtime/ModelUsageLedger.js +92 -0
- package/dist/runtime/ModelUsageLedger.js.map +1 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/skills/SkillDiscovery.js +1 -1
- package/dist/skills/SkillDiscovery.js.map +1 -1
- package/dist/tools/CommandOutputCompressor.d.ts +28 -0
- package/dist/tools/CommandOutputCompressor.js +242 -0
- package/dist/tools/CommandOutputCompressor.js.map +1 -0
- package/dist/tools/CommandRunLedger.d.ts +77 -0
- package/dist/tools/CommandRunLedger.js +111 -0
- package/dist/tools/CommandRunLedger.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/workflow/EngineeringStandards.js +91 -2
- package/dist/workflow/EngineeringStandards.js.map +1 -1
- package/dist/workflow/GovernanceTemplatePacks.js +2 -2
- package/dist/workflow/GovernanceTemplates.js +93 -92
- package/dist/workflow/GovernanceTemplates.js.map +1 -1
- package/dist/workflow/TaskLevelDetector.d.ts +41 -0
- package/dist/workflow/TaskLevelDetector.js +219 -0
- package/dist/workflow/TaskLevelDetector.js.map +1 -0
- package/dist/workflow/WorkflowOrchestrator.d.ts +59 -0
- package/dist/workflow/WorkflowOrchestrator.js +326 -0
- package/dist/workflow/WorkflowOrchestrator.js.map +1 -0
- package/dist/workflow/autonomous/BackgroundHunter.d.ts +74 -0
- package/dist/workflow/autonomous/BackgroundHunter.js +220 -0
- package/dist/workflow/autonomous/BackgroundHunter.js.map +1 -0
- package/dist/workflow/autonomous/index.d.ts +1 -0
- package/dist/workflow/autonomous/index.js +1 -0
- package/dist/workflow/autonomous/index.js.map +1 -1
- package/dist/workflow/gates/GateSystem.d.ts +33 -6
- package/dist/workflow/gates/GateSystem.js +176 -25
- package/dist/workflow/gates/GateSystem.js.map +1 -1
- package/dist/workflow/gates/MetaGovernanceGates.d.ts +70 -0
- package/dist/workflow/gates/MetaGovernanceGates.js +617 -0
- package/dist/workflow/gates/MetaGovernanceGates.js.map +1 -0
- package/dist/workflow/gates/VisualGate.d.ts +41 -0
- package/dist/workflow/gates/VisualGate.js +174 -0
- package/dist/workflow/gates/VisualGate.js.map +1 -0
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.js +1 -0
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/types.d.ts +6 -1
- package/docs/ACTIVE_SECURITY_VISUAL_GATES.md +87 -0
- package/docs/BACKGROUND_HUNTER.md +62 -0
- package/docs/CONTEXT_BUDGET.md +32 -6
- package/docs/DEPENDENCY_AUDIT.md +89 -0
- package/docs/EVOLUTION_SHADOW_MODE.md +63 -0
- package/docs/GOVERNANCE_DASHBOARD.md +21 -5
- package/docs/README.md +24 -12
- package/docs/start/README.md +29 -3
- package/docs/start/artifact-lifecycle.md +326 -0
- package/docs/start/workflow-upgrade.md +150 -0
- package/image/wechat-public.jpg +0 -0
- package/image/wxPay.jpg +0 -0
- package/image/zfb.jpg +0 -0
- 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
|
-
|
|
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
|
-
//
|
|
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);
|