@hongmaple0820/scale-engine 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/AiderAdapter.js +53 -53
- package/dist/adapters/AiderAdapter.js.map +1 -1
- package/dist/adapters/ClaudeCodeAdapter.js +2 -0
- package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
- package/dist/adapters/CodexAdapter.js +1 -1
- package/dist/adapters/CodexAdapter.js.map +1 -1
- package/dist/adapters/CursorAdapter.js +1 -1
- package/dist/adapters/CursorAdapter.js.map +1 -1
- package/dist/adapters/DeepSeekTuiAdapter.js +2 -0
- package/dist/adapters/DeepSeekTuiAdapter.js.map +1 -1
- package/dist/adapters/DoubaoAdapter.js +34 -34
- package/dist/adapters/DoubaoAdapter.js.map +1 -1
- package/dist/adapters/GeminiAdapter.js +1 -1
- package/dist/adapters/GeminiAdapter.js.map +1 -1
- package/dist/adapters/HermesAdapter.js +1 -1
- package/dist/adapters/HermesAdapter.js.map +1 -1
- package/dist/adapters/KimiAdapter.js +33 -33
- package/dist/adapters/KimiAdapter.js.map +1 -1
- package/dist/adapters/KiroAdapter.js +27 -27
- package/dist/adapters/KiroAdapter.js.map +1 -1
- package/dist/adapters/OpenClawAdapter.js +1 -1
- package/dist/adapters/OpenClawAdapter.js.map +1 -1
- package/dist/adapters/OpenCodeAdapter.js +1 -1
- package/dist/adapters/OpenCodeAdapter.js.map +1 -1
- package/dist/adapters/QCoderAdapter.js +1 -1
- package/dist/adapters/QCoderAdapter.js.map +1 -1
- package/dist/adapters/TraeAdapter.js +1 -1
- package/dist/adapters/TraeAdapter.js.map +1 -1
- package/dist/adapters/VSCAdapter.js +1 -1
- package/dist/adapters/VSCAdapter.js.map +1 -1
- package/dist/adapters/WindsurfAdapter.js +33 -33
- package/dist/adapters/WindsurfAdapter.js.map +1 -1
- package/dist/adapters/WorkBuddyAdapter.js +1 -1
- package/dist/adapters/WorkBuddyAdapter.js.map +1 -1
- package/dist/api/cli.js +365 -13
- package/dist/api/cli.js.map +1 -1
- package/dist/api/doctor.d.ts +1 -0
- package/dist/api/doctor.js +29 -0
- package/dist/api/doctor.js.map +1 -1
- package/dist/api/quickstart.d.ts +1 -0
- package/dist/api/quickstart.js +2 -2
- package/dist/api/quickstart.js.map +1 -1
- package/dist/cli/phaseCommands.d.ts +5 -0
- package/dist/cli/phaseCommands.js +149 -25
- package/dist/cli/phaseCommands.js.map +1 -1
- package/dist/skills/ExternalSkills.js +2 -0
- package/dist/skills/ExternalSkills.js.map +1 -1
- package/dist/skills/SkillCatalog.d.ts +13 -0
- package/dist/skills/SkillCatalog.js +184 -0
- package/dist/skills/SkillCatalog.js.map +1 -0
- package/dist/skills/SkillDoctor.d.ts +37 -0
- package/dist/skills/SkillDoctor.js +90 -0
- package/dist/skills/SkillDoctor.js.map +1 -0
- package/dist/skills/index.d.ts +1 -0
- package/dist/skills/index.js +1 -0
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/routing/SkillGate.d.ts +2 -1
- package/dist/skills/routing/SkillGate.js +19 -2
- package/dist/skills/routing/SkillGate.js.map +1 -1
- package/dist/skills/routing/SkillPlanner.js +40 -40
- package/dist/skills/routing/SkillPolicy.js +39 -12
- package/dist/skills/routing/SkillPolicy.js.map +1 -1
- package/dist/workflow/GovernanceLock.d.ts +35 -0
- package/dist/workflow/GovernanceLock.js +58 -0
- package/dist/workflow/GovernanceLock.js.map +1 -0
- package/dist/workflow/GovernanceTemplatePacks.d.ts +24 -0
- package/dist/workflow/GovernanceTemplatePacks.js +128 -0
- package/dist/workflow/GovernanceTemplatePacks.js.map +1 -0
- package/dist/workflow/GovernanceTemplates.d.ts +6 -1
- package/dist/workflow/GovernanceTemplates.js +585 -414
- package/dist/workflow/GovernanceTemplates.js.map +1 -1
- package/dist/workflow/TaskArtifactScaffolder.js +17 -17
- package/dist/workflow/TaskArtifactScaffolder.js.map +1 -1
- package/dist/workflow/VerificationCommands.js +1 -8
- package/dist/workflow/VerificationCommands.js.map +1 -1
- package/dist/workflow/VerificationProfile.d.ts +1 -0
- package/dist/workflow/VerificationProfile.js +42 -5
- package/dist/workflow/VerificationProfile.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts +6 -3
- package/dist/workflow/WorkflowEngine.js +1 -1
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/dist/workflow/WorkspaceLifecycle.d.ts +53 -0
- package/dist/workflow/WorkspaceLifecycle.js +285 -0
- package/dist/workflow/WorkspaceLifecycle.js.map +1 -0
- package/dist/workflow/WorkspaceTopology.d.ts +49 -0
- package/dist/workflow/WorkspaceTopology.js +125 -0
- package/dist/workflow/WorkspaceTopology.js.map +1 -0
- package/dist/workflow/index.d.ts +4 -0
- package/dist/workflow/index.js +4 -0
- package/dist/workflow/index.js.map +1 -1
- package/package.json +2 -2
package/dist/api/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ import { LessonExtractor, RuleProposer, HookGenerator, EvolutionEngine } from '.
|
|
|
22
22
|
import { Doctor } from './doctor.js';
|
|
23
23
|
import { quickStart, detectPlatform } from './quickstart.js';
|
|
24
24
|
import { SkillDiscovery } from '../skills/SkillDiscovery.js';
|
|
25
|
+
import { inspectRequiredWorkflowSkills, inspectWorkflowSkills } from '../skills/SkillDoctor.js';
|
|
25
26
|
import { listWorkflowPresets, getPresetsByScenario } from '../workflows/presets.js';
|
|
26
27
|
import { EvidenceStore } from '../workflow/EvidenceStore.js';
|
|
27
28
|
import { OutOfScopeStore } from '../workflow/OutOfScopeStore.js';
|
|
@@ -29,9 +30,12 @@ import { ReviewStore } from '../workflow/ReviewStore.js';
|
|
|
29
30
|
import { WorkflowEngine } from '../workflow/WorkflowEngine.js';
|
|
30
31
|
import { resolveVerificationTargets } from '../workflow/VerificationProfile.js';
|
|
31
32
|
import { writeGovernanceTemplates } from '../workflow/GovernanceTemplates.js';
|
|
33
|
+
import { computeGovernanceDrift } from '../workflow/GovernanceLock.js';
|
|
32
34
|
import { TaskMetricsStore } from '../workflow/TaskMetricsStore.js';
|
|
33
35
|
import { checkTaskArtifactCompleteness } from '../workflow/TaskArtifactScaffolder.js';
|
|
34
36
|
import { WorkflowArtifactWriter } from '../workflow/WorkflowArtifactWriter.js';
|
|
37
|
+
import { cleanupWorkspaceLifecycle, inspectWorkspaceLifecycle, } from '../workflow/WorkspaceLifecycle.js';
|
|
38
|
+
import { resolveWorkspaceTopology, workspaceTopologyPath, workspaceTopologyTemplate, } from '../workflow/WorkspaceTopology.js';
|
|
35
39
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
36
40
|
import { join, resolve } from 'node:path';
|
|
37
41
|
// ============================================================================
|
|
@@ -54,6 +58,17 @@ function ensureDir(dir) {
|
|
|
54
58
|
function isTruthyFlag(value) {
|
|
55
59
|
return value === true || value === '' || value === 'true' || value === '1';
|
|
56
60
|
}
|
|
61
|
+
function normalizePreflightProfile(value) {
|
|
62
|
+
const normalized = String(value ?? 'quick').trim().toLowerCase();
|
|
63
|
+
if (normalized === 'full' || normalized === 'ci')
|
|
64
|
+
return normalized;
|
|
65
|
+
return 'quick';
|
|
66
|
+
}
|
|
67
|
+
function gatesForPreflightProfile(profile) {
|
|
68
|
+
if (profile === 'quick')
|
|
69
|
+
return ['G3', 'G0', 'G4', 'G5'];
|
|
70
|
+
return ['G3', 'G0', 'G4', 'G5', 'G6', 'G7'];
|
|
71
|
+
}
|
|
57
72
|
let _engine = null;
|
|
58
73
|
function getEngine() {
|
|
59
74
|
if (!_engine)
|
|
@@ -810,6 +825,179 @@ const taskArtifacts = defineCommand({
|
|
|
810
825
|
meta: { name: 'task-artifacts', description: 'Inspect task artifact completeness' },
|
|
811
826
|
subCommands: { check: taskArtifactsCheck },
|
|
812
827
|
});
|
|
828
|
+
function printWorkspaceLifecycle(report) {
|
|
829
|
+
console.log('\nSCALE Workspace Lifecycle');
|
|
830
|
+
console.log(` Topology: ${report.topology.topology}${report.topology.configured ? '' : ' (default)'}`);
|
|
831
|
+
console.log(` Root: ${report.root.path}`);
|
|
832
|
+
console.log(` Branch: ${report.root.branch ?? '(detached)'}`);
|
|
833
|
+
console.log(` Linked worktree: ${report.root.isLinkedWorktree ? 'yes' : 'no'}`);
|
|
834
|
+
console.log(` Root status: ${report.root.clean ? 'clean' : 'dirty'}`);
|
|
835
|
+
if (!report.root.clean) {
|
|
836
|
+
console.log(` staged=${report.root.staged} unstaged=${report.root.unstaged} untracked=${report.root.untracked}`);
|
|
837
|
+
}
|
|
838
|
+
if (report.childRepositories.length) {
|
|
839
|
+
console.log('\n Child repositories:');
|
|
840
|
+
for (const child of report.childRepositories) {
|
|
841
|
+
console.log(` ${child.clean ? '[CLEAN]' : '[DIRTY]'} ${child.relativePath} (${child.kind}) branch=${child.branch ?? '(detached)'}`);
|
|
842
|
+
if (!child.clean)
|
|
843
|
+
console.log(` staged=${child.staged} unstaged=${child.unstaged} untracked=${child.untracked}`);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
console.log('\n Child repositories: none');
|
|
848
|
+
}
|
|
849
|
+
console.log(`\n Cleanup candidate: ${report.finish.canCleanup ? 'yes' : 'no'}`);
|
|
850
|
+
for (const blocker of report.finish.blockers)
|
|
851
|
+
console.log(` [BLOCKER] ${blocker}`);
|
|
852
|
+
for (const warning of report.finish.warnings)
|
|
853
|
+
console.log(` [WARN] ${warning}`);
|
|
854
|
+
for (const action of report.finish.nextActions)
|
|
855
|
+
console.log(` [NEXT] ${action}`);
|
|
856
|
+
}
|
|
857
|
+
function printWorkspaceTopology(topology, written) {
|
|
858
|
+
console.log('\nSCALE Workspace Topology');
|
|
859
|
+
console.log(` Topology: ${topology.topology}${topology.configured ? '' : ' (default)'}`);
|
|
860
|
+
console.log(` Config: ${topology.configPath}`);
|
|
861
|
+
if (written)
|
|
862
|
+
console.log(` Written: ${written}`);
|
|
863
|
+
console.log('\n Repositories:');
|
|
864
|
+
for (const repo of topology.repositories) {
|
|
865
|
+
console.log(` - ${repo.name}: ${repo.path} (${repo.role}) required=${repo.required !== false ? 'yes' : 'no'}`);
|
|
866
|
+
}
|
|
867
|
+
for (const warning of topology.warnings)
|
|
868
|
+
console.log(` [WARN] ${warning}`);
|
|
869
|
+
}
|
|
870
|
+
function printWorkspaceCleanup(result) {
|
|
871
|
+
printWorkspaceLifecycle(result.report);
|
|
872
|
+
console.log('\n Cleanup plan:');
|
|
873
|
+
console.log(` Mode: ${result.mode}`);
|
|
874
|
+
console.log(` Target: ${result.targetPath}`);
|
|
875
|
+
console.log(` Can apply: ${result.canApply ? 'yes' : 'no'}`);
|
|
876
|
+
console.log(` Applied: ${result.applied ? 'yes' : 'no'}`);
|
|
877
|
+
console.log(` Confirmation token: ${result.confirmationToken ?? '(unavailable)'}`);
|
|
878
|
+
for (const command of result.commands)
|
|
879
|
+
console.log(` Command: ${command}`);
|
|
880
|
+
for (const blocker of result.blockers)
|
|
881
|
+
console.log(` [BLOCKER] ${blocker}`);
|
|
882
|
+
for (const warning of result.warnings)
|
|
883
|
+
console.log(` [WARN] ${warning}`);
|
|
884
|
+
}
|
|
885
|
+
const workspaceStatus = defineCommand({
|
|
886
|
+
meta: { name: 'status', description: 'Inspect root worktree and child repository lifecycle state' },
|
|
887
|
+
args: {
|
|
888
|
+
dir: { type: 'string', description: 'Repository or worktree directory; defaults to current project directory' },
|
|
889
|
+
json: { type: 'boolean', default: false },
|
|
890
|
+
},
|
|
891
|
+
async run({ args }) {
|
|
892
|
+
const report = await inspectWorkspaceLifecycle({ projectDir: args.dir ?? PROJECT_DIR });
|
|
893
|
+
if (args.json) {
|
|
894
|
+
console.log(JSON.stringify(report, null, 2));
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
printWorkspaceLifecycle(report);
|
|
898
|
+
}
|
|
899
|
+
if (report.finish.blockers.length > 0)
|
|
900
|
+
process.exitCode = 1;
|
|
901
|
+
},
|
|
902
|
+
});
|
|
903
|
+
const workspaceMap = defineCommand({
|
|
904
|
+
meta: { name: 'map', description: 'Resolve or write explicit workspace topology for single, monorepo, polyrepo, submodule, or MOE projects' },
|
|
905
|
+
args: {
|
|
906
|
+
dir: { type: 'string', description: 'Project directory; defaults to current project directory' },
|
|
907
|
+
topology: { type: 'string', default: 'moe', description: 'Starter topology for --write (single/monorepo/polyrepo/submodule-workspace/moe)' },
|
|
908
|
+
write: { type: 'boolean', default: false, description: 'Create .scale/workspace.json when it does not exist' },
|
|
909
|
+
json: { type: 'boolean', default: false },
|
|
910
|
+
},
|
|
911
|
+
run({ args }) {
|
|
912
|
+
const projectDir = resolve(args.dir ?? PROJECT_DIR);
|
|
913
|
+
const target = workspaceTopologyPath(projectDir);
|
|
914
|
+
let written = null;
|
|
915
|
+
if (isTruthyFlag(args.write) && !existsSync(target)) {
|
|
916
|
+
ensureDir(join(projectDir, '.scale'));
|
|
917
|
+
writeFileSync(target, workspaceTopologyTemplate({
|
|
918
|
+
topology: normalizeWorkspaceTopologyKind(args.topology),
|
|
919
|
+
}), 'utf-8');
|
|
920
|
+
written = target;
|
|
921
|
+
}
|
|
922
|
+
const topology = resolveWorkspaceTopology({ projectDir });
|
|
923
|
+
const result = { ...topology, written };
|
|
924
|
+
if (args.json) {
|
|
925
|
+
console.log(JSON.stringify(result, null, 2));
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
printWorkspaceTopology(topology, written);
|
|
929
|
+
}
|
|
930
|
+
},
|
|
931
|
+
});
|
|
932
|
+
const workspaceFinish = defineCommand({
|
|
933
|
+
meta: { name: 'finish', description: 'Check whether a temporary worktree can be safely finished or cleaned up' },
|
|
934
|
+
args: {
|
|
935
|
+
dir: { type: 'string', description: 'Repository or worktree directory; defaults to current project directory' },
|
|
936
|
+
json: { type: 'boolean', default: false },
|
|
937
|
+
},
|
|
938
|
+
async run({ args }) {
|
|
939
|
+
const report = await inspectWorkspaceLifecycle({ projectDir: args.dir ?? PROJECT_DIR });
|
|
940
|
+
const result = {
|
|
941
|
+
root: report.root,
|
|
942
|
+
childRepositories: report.childRepositories,
|
|
943
|
+
topology: report.topology,
|
|
944
|
+
finish: report.finish,
|
|
945
|
+
};
|
|
946
|
+
if (args.json) {
|
|
947
|
+
console.log(JSON.stringify(result, null, 2));
|
|
948
|
+
}
|
|
949
|
+
else {
|
|
950
|
+
printWorkspaceLifecycle(report);
|
|
951
|
+
}
|
|
952
|
+
if (report.finish.blockers.length > 0)
|
|
953
|
+
process.exitCode = 1;
|
|
954
|
+
},
|
|
955
|
+
});
|
|
956
|
+
const workspaceCleanup = defineCommand({
|
|
957
|
+
meta: { name: 'cleanup', description: 'Dry-run or apply safe removal of a linked temporary worktree' },
|
|
958
|
+
args: {
|
|
959
|
+
dir: { type: 'string', description: 'Linked worktree directory; defaults to current project directory' },
|
|
960
|
+
'dry-run': { type: 'boolean', default: false, description: 'Preview cleanup; this is the default unless --apply is set' },
|
|
961
|
+
apply: { type: 'boolean', default: false, description: 'Actually run git worktree remove after safety checks' },
|
|
962
|
+
confirm: { type: 'string', description: 'Required confirmation token for --apply, usually the worktree branch name' },
|
|
963
|
+
json: { type: 'boolean', default: false },
|
|
964
|
+
},
|
|
965
|
+
async run({ args }) {
|
|
966
|
+
const result = await cleanupWorkspaceLifecycle({
|
|
967
|
+
projectDir: args.dir ?? PROJECT_DIR,
|
|
968
|
+
apply: isTruthyFlag(args.apply),
|
|
969
|
+
confirm: args.confirm,
|
|
970
|
+
});
|
|
971
|
+
if (args.json) {
|
|
972
|
+
console.log(JSON.stringify(result, null, 2));
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
printWorkspaceCleanup(result);
|
|
976
|
+
}
|
|
977
|
+
if (!result.canApply || (isTruthyFlag(args.apply) && !result.applied))
|
|
978
|
+
process.exitCode = 1;
|
|
979
|
+
},
|
|
980
|
+
});
|
|
981
|
+
const workspace = defineCommand({
|
|
982
|
+
meta: { name: 'workspace', description: 'Inspect worktree, branch, and child repository lifecycle safety' },
|
|
983
|
+
subCommands: {
|
|
984
|
+
map: workspaceMap,
|
|
985
|
+
status: workspaceStatus,
|
|
986
|
+
finish: workspaceFinish,
|
|
987
|
+
cleanup: workspaceCleanup,
|
|
988
|
+
},
|
|
989
|
+
});
|
|
990
|
+
function normalizeWorkspaceTopologyKind(value) {
|
|
991
|
+
const normalized = String(value ?? 'moe').trim();
|
|
992
|
+
if (normalized === 'single'
|
|
993
|
+
|| normalized === 'monorepo'
|
|
994
|
+
|| normalized === 'polyrepo'
|
|
995
|
+
|| normalized === 'submodule-workspace'
|
|
996
|
+
|| normalized === 'moe') {
|
|
997
|
+
return normalized;
|
|
998
|
+
}
|
|
999
|
+
return 'moe';
|
|
1000
|
+
}
|
|
813
1001
|
const preflight = defineCommand({
|
|
814
1002
|
meta: { name: 'preflight', description: 'Run service-aware verification without a task artifact' },
|
|
815
1003
|
args: {
|
|
@@ -818,6 +1006,7 @@ const preflight = defineCommand({
|
|
|
818
1006
|
'test-cmd': { type: 'string', description: 'Override test command' },
|
|
819
1007
|
'coverage-cmd': { type: 'string', description: 'Override coverage command' },
|
|
820
1008
|
profile: { type: 'string', description: 'Verification profile from .scale/verification.json' },
|
|
1009
|
+
'preflight-profile': { type: 'string', default: 'quick', description: 'Gate intensity profile (quick/full/ci); quick skips coverage and security' },
|
|
821
1010
|
service: { type: 'string', description: 'Service name from .scale/verification.json; use all for required services' },
|
|
822
1011
|
'tdd-evidence': { type: 'string', description: 'Path to JSON TDD evidence with red/green/refactor/testFirst=true' },
|
|
823
1012
|
'tdd-strict': { type: 'boolean', default: false, description: 'Require TDD evidence before other gates' },
|
|
@@ -825,6 +1014,8 @@ const preflight = defineCommand({
|
|
|
825
1014
|
},
|
|
826
1015
|
async run({ args }) {
|
|
827
1016
|
const { workflowEngine } = getEngine();
|
|
1017
|
+
const preflightProfile = normalizePreflightProfile(args['preflight-profile']);
|
|
1018
|
+
const gateStages = gatesForPreflightProfile(preflightProfile);
|
|
828
1019
|
const resolved = resolveVerificationTargets({
|
|
829
1020
|
projectDir: PROJECT_DIR,
|
|
830
1021
|
scaleDir: SCALE_DIR,
|
|
@@ -837,6 +1028,8 @@ const preflight = defineCommand({
|
|
|
837
1028
|
for (const warning of resolved.warnings)
|
|
838
1029
|
console.log(` [WARN] ${warning}`);
|
|
839
1030
|
console.log(` Profile: ${resolved.profileName}`);
|
|
1031
|
+
console.log(` Preflight profile: ${preflightProfile}`);
|
|
1032
|
+
console.log(` Gates: ${gateStages.join(', ')}`);
|
|
840
1033
|
}
|
|
841
1034
|
for (const target of resolved.targets) {
|
|
842
1035
|
if (!args.json) {
|
|
@@ -851,6 +1044,7 @@ const preflight = defineCommand({
|
|
|
851
1044
|
coverage: args['coverage-cmd'] ?? target.config.coverage,
|
|
852
1045
|
tddEvidence: args['tdd-evidence'],
|
|
853
1046
|
tddStrict: isTruthyFlag(args['tdd-strict']),
|
|
1047
|
+
gates: gateStages,
|
|
854
1048
|
});
|
|
855
1049
|
const passed = gates.every(gate => gate.passed);
|
|
856
1050
|
targetResults.push({
|
|
@@ -871,6 +1065,8 @@ const preflight = defineCommand({
|
|
|
871
1065
|
const result = {
|
|
872
1066
|
phase: 'PREFLIGHT',
|
|
873
1067
|
profile: resolved.profileName,
|
|
1068
|
+
preflightProfile,
|
|
1069
|
+
gates: gateStages,
|
|
874
1070
|
services: targetResults.map(target => target.service).filter(Boolean),
|
|
875
1071
|
policy: resolved.policy,
|
|
876
1072
|
targets: targetResults,
|
|
@@ -1006,7 +1202,13 @@ const init = defineCommand({
|
|
|
1006
1202
|
args: {
|
|
1007
1203
|
agent: { type: 'string', default: '', description: `Agent type (${SUPPORTED_AGENTS.join('/')}) - auto-detected if not specified` },
|
|
1008
1204
|
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
1205
|
+
json: { type: 'boolean', default: false, description: 'Output initialization result as JSON' },
|
|
1009
1206
|
scenario: { type: 'string', default: 'standard', description: 'Scenario mode (sandbox/standard/critical)' },
|
|
1207
|
+
'governance-pack': {
|
|
1208
|
+
type: 'string',
|
|
1209
|
+
default: 'standard',
|
|
1210
|
+
description: 'Governance template pack (standard/project-scaffold/moe-workspace/go-service-matrix/node-library/frontend-app)',
|
|
1211
|
+
},
|
|
1010
1212
|
quick: { type: 'boolean', default: false, description: 'Quick start with auto-detection' },
|
|
1011
1213
|
interactive: { type: 'boolean', default: false, description: 'Interactive configuration mode with prompts' },
|
|
1012
1214
|
'coverage-threshold': { type: 'string', default: '80', description: 'Coverage threshold (default 80%)' },
|
|
@@ -1067,6 +1269,7 @@ const init = defineCommand({
|
|
|
1067
1269
|
const governance = writeGovernanceTemplates(args.dir, {
|
|
1068
1270
|
mode: governanceModeFromScenario(scenarioMode),
|
|
1069
1271
|
projectName,
|
|
1272
|
+
pack: args['governance-pack'],
|
|
1070
1273
|
});
|
|
1071
1274
|
result.created.push(...governance.created);
|
|
1072
1275
|
result.skipped.push(...governance.skipped);
|
|
@@ -1091,8 +1294,24 @@ const init = defineCommand({
|
|
|
1091
1294
|
return;
|
|
1092
1295
|
}
|
|
1093
1296
|
// One-click quick start mode
|
|
1094
|
-
if (
|
|
1095
|
-
const qsResult = await quickStart(args.dir);
|
|
1297
|
+
if (!args.agent) {
|
|
1298
|
+
const qsResult = await quickStart(args.dir, { governancePack: args['governance-pack'] });
|
|
1299
|
+
if (args.json) {
|
|
1300
|
+
const detection = qsResult.success ? undefined : detectPlatform(args.dir);
|
|
1301
|
+
console.log(JSON.stringify({
|
|
1302
|
+
ok: qsResult.success,
|
|
1303
|
+
mode: 'quick',
|
|
1304
|
+
platform: qsResult.platform,
|
|
1305
|
+
created: qsResult.created,
|
|
1306
|
+
skipped: qsResult.skipped,
|
|
1307
|
+
constraintsApplied: qsResult.constraintsApplied,
|
|
1308
|
+
capabilitiesEnabled: qsResult.capabilitiesEnabled,
|
|
1309
|
+
knowledgeGraph: qsResult.knowledgeGraph,
|
|
1310
|
+
nextSteps: qsResult.nextSteps,
|
|
1311
|
+
suggestions: detection?.suggestions ?? [],
|
|
1312
|
+
}, null, 2));
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1096
1315
|
if (qsResult.success && qsResult.platform) {
|
|
1097
1316
|
console.log(`\n✅ SCALE Engine Quick Start completed for ${qsResult.platform}`);
|
|
1098
1317
|
console.log(`\n📁 Created (${qsResult.created.length}):`);
|
|
@@ -1124,9 +1343,26 @@ const init = defineCommand({
|
|
|
1124
1343
|
const governance = writeGovernanceTemplates(args.dir, {
|
|
1125
1344
|
mode: governanceModeFromScenario(args.scenario),
|
|
1126
1345
|
projectName,
|
|
1346
|
+
pack: args['governance-pack'],
|
|
1127
1347
|
});
|
|
1128
1348
|
result.created.push(...governance.created);
|
|
1129
1349
|
result.skipped.push(...governance.skipped);
|
|
1350
|
+
if (args.json) {
|
|
1351
|
+
console.log(JSON.stringify({
|
|
1352
|
+
ok: true,
|
|
1353
|
+
mode: args.quick ? 'quick-agent' : 'manual',
|
|
1354
|
+
agent: args.agent,
|
|
1355
|
+
scenario: args.scenario,
|
|
1356
|
+
governancePack: args['governance-pack'],
|
|
1357
|
+
settingsPath: result.settingsPath,
|
|
1358
|
+
knowledgeDocPath: result.knowledgeDocPath,
|
|
1359
|
+
scaleDir: result.scaleDir,
|
|
1360
|
+
created: result.created,
|
|
1361
|
+
skipped: result.skipped,
|
|
1362
|
+
nextSteps: ['scale doctor', 'scale create Spec "<feature name>"'],
|
|
1363
|
+
}, null, 2));
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1130
1366
|
console.log(`\n✅ SCALE Engine initialized for ${args.agent} (scenario: ${args.scenario})`);
|
|
1131
1367
|
console.log(`\n📁 Created:`);
|
|
1132
1368
|
for (const f of result.created)
|
|
@@ -1145,6 +1381,39 @@ const init = defineCommand({
|
|
|
1145
1381
|
},
|
|
1146
1382
|
});
|
|
1147
1383
|
// ============================================================================
|
|
1384
|
+
// governance command — Generated governance asset tooling
|
|
1385
|
+
// ============================================================================
|
|
1386
|
+
const governanceDiff = defineCommand({
|
|
1387
|
+
meta: { name: 'diff', description: 'Check generated governance files for drift' },
|
|
1388
|
+
args: {
|
|
1389
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
1390
|
+
json: { type: 'boolean', default: false, description: 'Print JSON output' },
|
|
1391
|
+
},
|
|
1392
|
+
run({ args }) {
|
|
1393
|
+
const report = computeGovernanceDrift(args.dir);
|
|
1394
|
+
if (args.json) {
|
|
1395
|
+
console.log(JSON.stringify(report, null, 2));
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (!report.lockExists) {
|
|
1399
|
+
console.log('No governance lock found. Run: scale init --governance-pack <pack>');
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
if (report.missing.length === 0 && report.changed.length === 0) {
|
|
1403
|
+
console.log('Governance generated files are clean.');
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
for (const item of report.missing)
|
|
1407
|
+
console.log(`missing: ${item.path}`);
|
|
1408
|
+
for (const item of report.changed)
|
|
1409
|
+
console.log(`changed: ${item.path}`);
|
|
1410
|
+
},
|
|
1411
|
+
});
|
|
1412
|
+
const governance = defineCommand({
|
|
1413
|
+
meta: { name: 'governance', description: 'Governance template pack tools' },
|
|
1414
|
+
subCommands: { diff: governanceDiff },
|
|
1415
|
+
});
|
|
1416
|
+
// ============================================================================
|
|
1148
1417
|
// evolve command
|
|
1149
1418
|
// ============================================================================
|
|
1150
1419
|
const evolve = defineCommand({
|
|
@@ -1188,11 +1457,29 @@ const workflowList = defineCommand({
|
|
|
1188
1457
|
meta: { name: 'list', description: 'List all workflow presets' },
|
|
1189
1458
|
args: {
|
|
1190
1459
|
scenario: { type: 'string', description: 'Filter by scenario mode (sandbox/standard/critical)' },
|
|
1460
|
+
json: { type: 'boolean', default: false, description: 'Output workflow presets as JSON' },
|
|
1191
1461
|
},
|
|
1192
1462
|
async run({ args }) {
|
|
1193
1463
|
const presets = args.scenario
|
|
1194
1464
|
? getPresetsByScenario(args.scenario)
|
|
1195
1465
|
: listWorkflowPresets();
|
|
1466
|
+
if (args.json) {
|
|
1467
|
+
console.log(JSON.stringify({
|
|
1468
|
+
ok: true,
|
|
1469
|
+
scenario: args.scenario ?? null,
|
|
1470
|
+
count: presets.length,
|
|
1471
|
+
presets: presets.map(preset => ({
|
|
1472
|
+
id: preset.id,
|
|
1473
|
+
name: preset.name,
|
|
1474
|
+
nameZh: preset.nameZh,
|
|
1475
|
+
description: preset.description,
|
|
1476
|
+
scenarioMode: preset.scenarioMode,
|
|
1477
|
+
requiredArtifacts: preset.requiredArtifacts,
|
|
1478
|
+
steps: preset.steps,
|
|
1479
|
+
})),
|
|
1480
|
+
}, null, 2));
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1196
1483
|
if (presets.length === 0) {
|
|
1197
1484
|
console.log('No workflow presets found.');
|
|
1198
1485
|
return;
|
|
@@ -1366,15 +1653,34 @@ const skillScan = defineCommand({
|
|
|
1366
1653
|
meta: { name: 'scan', description: 'Scan for installed skills' },
|
|
1367
1654
|
args: {
|
|
1368
1655
|
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
1656
|
+
json: { type: 'boolean', default: false, description: 'Output scan result as JSON' },
|
|
1369
1657
|
},
|
|
1370
1658
|
async run({ args }) {
|
|
1371
1659
|
const discovery = new SkillDiscovery(args.dir);
|
|
1372
1660
|
const platform = discovery.detectPlatform();
|
|
1661
|
+
if (!platform && args.json) {
|
|
1662
|
+
console.log(JSON.stringify({
|
|
1663
|
+
ok: false,
|
|
1664
|
+
platform: null,
|
|
1665
|
+
skills: [],
|
|
1666
|
+
message: 'No agent platform detected. Run `scale init` first.',
|
|
1667
|
+
}, null, 2));
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1373
1670
|
if (!platform) {
|
|
1374
1671
|
console.log('\n⚠️ No agent platform detected. Run `scale init` first.');
|
|
1375
1672
|
return;
|
|
1376
1673
|
}
|
|
1377
1674
|
const result = discovery.scanSkills(platform);
|
|
1675
|
+
if (args.json) {
|
|
1676
|
+
console.log(JSON.stringify({
|
|
1677
|
+
ok: true,
|
|
1678
|
+
platform: result.platform,
|
|
1679
|
+
count: result.skills.length,
|
|
1680
|
+
skills: result.skills,
|
|
1681
|
+
}, null, 2));
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1378
1684
|
console.log(`\n🔍 Platform: ${result.platform}`);
|
|
1379
1685
|
console.log(`📦 Skills found: ${result.skills.length}`);
|
|
1380
1686
|
if (result.skills.length > 0) {
|
|
@@ -1463,11 +1769,37 @@ const skillPlanCommand = defineCommand({
|
|
|
1463
1769
|
console.log(` Written: ${writtenPath}`);
|
|
1464
1770
|
},
|
|
1465
1771
|
});
|
|
1772
|
+
const skillDoctorCommand = defineCommand({
|
|
1773
|
+
meta: { name: 'doctor', description: 'Check workflow skill installation status' },
|
|
1774
|
+
args: {
|
|
1775
|
+
dir: { type: 'string', default: '.', description: 'Project directory' },
|
|
1776
|
+
json: { type: 'boolean', default: false, description: 'Output skill doctor report as JSON' },
|
|
1777
|
+
},
|
|
1778
|
+
run({ args }) {
|
|
1779
|
+
const report = inspectWorkflowSkills({ projectDir: args.dir });
|
|
1780
|
+
if (args.json) {
|
|
1781
|
+
console.log(JSON.stringify(report, null, 2));
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
console.log('\nSCALE Skill Doctor');
|
|
1785
|
+
console.log(` Installed: ${report.installed}/${report.total}`);
|
|
1786
|
+
for (const skill of report.skills) {
|
|
1787
|
+
console.log(` ${skill.installed ? '[OK]' : '[MISSING]'} ${skill.id}`);
|
|
1788
|
+
if (skill.detectedPath)
|
|
1789
|
+
console.log(` path: ${skill.detectedPath}`);
|
|
1790
|
+
if (!skill.installed)
|
|
1791
|
+
console.log(` install: ${skill.installCommand}`);
|
|
1792
|
+
}
|
|
1793
|
+
if (!report.ok)
|
|
1794
|
+
process.exitCode = 1;
|
|
1795
|
+
},
|
|
1796
|
+
});
|
|
1466
1797
|
const skillCheckCommand = defineCommand({
|
|
1467
1798
|
meta: { name: 'check', description: 'Check required skill evidence artifacts' },
|
|
1468
1799
|
args: {
|
|
1469
1800
|
dir: { type: 'string', description: 'Task artifact directory; defaults to current state artifactsDir' },
|
|
1470
1801
|
level: { type: 'string', description: 'Task level: S, M, L, or CRITICAL; defaults to current state level or M' },
|
|
1802
|
+
'require-installed': { type: 'boolean', default: false, description: 'Fail when required workflow skills are not installed locally' },
|
|
1471
1803
|
json: { type: 'boolean', default: false },
|
|
1472
1804
|
},
|
|
1473
1805
|
run({ args }) {
|
|
@@ -1482,33 +1814,51 @@ const skillCheckCommand = defineCommand({
|
|
|
1482
1814
|
mode: state?.skillRoutingMode ?? policy.policy.mode,
|
|
1483
1815
|
enforceLevels: policy.policy.enforceLevels,
|
|
1484
1816
|
});
|
|
1817
|
+
const skillInstallation = inspectRequiredWorkflowSkills(state?.requiredSkills ?? [], { projectDir: PROJECT_DIR });
|
|
1818
|
+
const requireInstalled = isTruthyFlag(args['require-installed']);
|
|
1819
|
+
const blocked = result.blocked || (requireInstalled && !skillInstallation.ok);
|
|
1820
|
+
const output = {
|
|
1821
|
+
...result,
|
|
1822
|
+
complete: result.complete && (!requireInstalled || skillInstallation.ok),
|
|
1823
|
+
blocked,
|
|
1824
|
+
skillInstallation: {
|
|
1825
|
+
...skillInstallation,
|
|
1826
|
+
checked: requireInstalled,
|
|
1827
|
+
},
|
|
1828
|
+
};
|
|
1485
1829
|
if (args.json) {
|
|
1486
|
-
console.log(JSON.stringify(
|
|
1830
|
+
console.log(JSON.stringify(output, null, 2));
|
|
1487
1831
|
return;
|
|
1488
1832
|
}
|
|
1489
|
-
console.log(`\nSkill Gate: ${
|
|
1490
|
-
console.log(` Mode: ${
|
|
1491
|
-
console.log(` Required: ${
|
|
1492
|
-
|
|
1833
|
+
console.log(`\nSkill Gate: ${output.complete ? 'COMPLETE' : 'INCOMPLETE'}`);
|
|
1834
|
+
console.log(` Mode: ${output.mode}`);
|
|
1835
|
+
console.log(` Required artifacts: ${output.required.join(', ') || 'none'}`);
|
|
1836
|
+
console.log(` Required skills: ${skillInstallation.required.join(', ') || 'none'}`);
|
|
1837
|
+
for (const file of output.missing)
|
|
1493
1838
|
console.log(` [MISSING] ${file}`);
|
|
1494
|
-
for (const item of
|
|
1839
|
+
for (const item of output.incomplete)
|
|
1495
1840
|
console.log(` [INCOMPLETE] ${item.file}: ${item.reason}`);
|
|
1496
|
-
if (
|
|
1841
|
+
if (requireInstalled && !skillInstallation.ok) {
|
|
1842
|
+
for (const skill of skillInstallation.skills.filter(skill => !skill.installed)) {
|
|
1843
|
+
console.log(` [MISSING_SKILL] ${skill.id}: ${skill.installCommand}`);
|
|
1844
|
+
}
|
|
1845
|
+
for (const skill of skillInstallation.unknown)
|
|
1846
|
+
console.log(` [UNKNOWN_SKILL] ${skill}`);
|
|
1847
|
+
}
|
|
1848
|
+
if (blocked)
|
|
1497
1849
|
process.exitCode = 1;
|
|
1498
1850
|
},
|
|
1499
1851
|
});
|
|
1500
1852
|
const skill = defineCommand({
|
|
1501
1853
|
meta: { name: 'skill', description: 'Skill discovery and management' },
|
|
1502
|
-
subCommands: { scan: skillScan, plan: skillPlanCommand, check: skillCheckCommand },
|
|
1854
|
+
subCommands: { scan: skillScan, doctor: skillDoctorCommand, plan: skillPlanCommand, check: skillCheckCommand },
|
|
1503
1855
|
});
|
|
1504
1856
|
// ============================================================================
|
|
1505
1857
|
// agent commands — Multi-Agent 协作系统 (Phase 9)
|
|
1506
1858
|
// ============================================================================
|
|
1507
1859
|
import { AgentPool } from '../agents/AgentPool.js';
|
|
1508
|
-
import { AgentChannel } from '../agents/AgentChannel.js';
|
|
1509
1860
|
import { PROFESSIONAL_AGENTS, getProfile, listProfiles } from '../agents/profiles.js';
|
|
1510
1861
|
const agentPool = new AgentPool();
|
|
1511
|
-
const agentChannel = new AgentChannel(getEngine().eventBus);
|
|
1512
1862
|
const agentSpawn = defineCommand({
|
|
1513
1863
|
meta: { name: 'spawn', description: 'Spawn a new agent instance' },
|
|
1514
1864
|
args: {
|
|
@@ -1626,7 +1976,7 @@ import * as phaseCommands from '../cli/phaseCommands.js';
|
|
|
1626
1976
|
import * as liteCommands from '../cli/liteCommands.js';
|
|
1627
1977
|
import * as vibeCommands from '../cli/vibeCommands.js';
|
|
1628
1978
|
const main = defineCommand({
|
|
1629
|
-
meta: { name: 'scale', version: '0.13.0', description: 'SCALE Engine v0.13.0 CLI - hardened phase workflow gates
|
|
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' },
|
|
1630
1980
|
subCommands: {
|
|
1631
1981
|
// Lite Mode (agent-skills style interactive entry)
|
|
1632
1982
|
lite: liteCommands.liteCommand,
|
|
@@ -1657,8 +2007,10 @@ const main = defineCommand({
|
|
|
1657
2007
|
evolve,
|
|
1658
2008
|
stats,
|
|
1659
2009
|
preflight,
|
|
2010
|
+
governance,
|
|
1660
2011
|
metrics,
|
|
1661
2012
|
'task-artifacts': taskArtifacts,
|
|
2013
|
+
workspace,
|
|
1662
2014
|
status,
|
|
1663
2015
|
workflow,
|
|
1664
2016
|
evidence,
|