@hongmaple0820/scale-engine 0.12.3 → 0.14.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 (157) hide show
  1. package/dist/adapters/AiderAdapter.js +1 -1
  2. package/dist/adapters/AiderAdapter.js.map +1 -1
  3. package/dist/adapters/ClaudeCodeAdapter.d.ts +1 -0
  4. package/dist/adapters/ClaudeCodeAdapter.js +5 -3
  5. package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
  6. package/dist/adapters/CodexAdapter.js +1 -1
  7. package/dist/adapters/CodexAdapter.js.map +1 -1
  8. package/dist/adapters/CursorAdapter.js +1 -1
  9. package/dist/adapters/CursorAdapter.js.map +1 -1
  10. package/dist/adapters/DeepSeekTuiAdapter.js +5 -3
  11. package/dist/adapters/DeepSeekTuiAdapter.js.map +1 -1
  12. package/dist/adapters/DoubaoAdapter.js +1 -1
  13. package/dist/adapters/DoubaoAdapter.js.map +1 -1
  14. package/dist/adapters/GeminiAdapter.js +1 -1
  15. package/dist/adapters/GeminiAdapter.js.map +1 -1
  16. package/dist/adapters/HermesAdapter.js +1 -1
  17. package/dist/adapters/HermesAdapter.js.map +1 -1
  18. package/dist/adapters/KimiAdapter.js +1 -1
  19. package/dist/adapters/KimiAdapter.js.map +1 -1
  20. package/dist/adapters/KiroAdapter.d.ts +14 -0
  21. package/dist/adapters/KiroAdapter.js +180 -0
  22. package/dist/adapters/KiroAdapter.js.map +1 -0
  23. package/dist/adapters/OpenClawAdapter.js +1 -1
  24. package/dist/adapters/OpenClawAdapter.js.map +1 -1
  25. package/dist/adapters/OpenCodeAdapter.js +1 -1
  26. package/dist/adapters/OpenCodeAdapter.js.map +1 -1
  27. package/dist/adapters/QCoderAdapter.js +1 -1
  28. package/dist/adapters/QCoderAdapter.js.map +1 -1
  29. package/dist/adapters/TraeAdapter.js +1 -1
  30. package/dist/adapters/TraeAdapter.js.map +1 -1
  31. package/dist/adapters/VSCAdapter.js +1 -1
  32. package/dist/adapters/VSCAdapter.js.map +1 -1
  33. package/dist/adapters/WindsurfAdapter.js +1 -1
  34. package/dist/adapters/WindsurfAdapter.js.map +1 -1
  35. package/dist/adapters/WorkBuddyAdapter.js +1 -1
  36. package/dist/adapters/WorkBuddyAdapter.js.map +1 -1
  37. package/dist/adapters/index.d.ts +1 -0
  38. package/dist/adapters/index.js +3 -0
  39. package/dist/adapters/index.js.map +1 -1
  40. package/dist/api/cli.js +690 -9
  41. package/dist/api/cli.js.map +1 -1
  42. package/dist/api/doctor.d.ts +13 -0
  43. package/dist/api/doctor.js +261 -5
  44. package/dist/api/doctor.js.map +1 -1
  45. package/dist/api/quickstart.d.ts +20 -1
  46. package/dist/api/quickstart.js +104 -3
  47. package/dist/api/quickstart.js.map +1 -1
  48. package/dist/artifact/types.d.ts +16 -2
  49. package/dist/artifact/types.js.map +1 -1
  50. package/dist/cli/phaseCommands.d.ts +66 -0
  51. package/dist/cli/phaseCommands.js +695 -51
  52. package/dist/cli/phaseCommands.js.map +1 -1
  53. package/dist/guardrails/detectors.d.ts +9 -0
  54. package/dist/guardrails/detectors.js +102 -0
  55. package/dist/guardrails/detectors.js.map +1 -1
  56. package/dist/hooks/HookGeneratorEnhanced.js +29 -0
  57. package/dist/hooks/HookGeneratorEnhanced.js.map +1 -1
  58. package/dist/hooks/WorkflowHooksManager.js +20 -1
  59. package/dist/hooks/WorkflowHooksManager.js.map +1 -1
  60. package/dist/index.d.ts +6 -0
  61. package/dist/index.js +4 -0
  62. package/dist/index.js.map +1 -1
  63. package/dist/output/BrandThemeLoader.d.ts +54 -0
  64. package/dist/output/BrandThemeLoader.js +340 -0
  65. package/dist/output/BrandThemeLoader.js.map +1 -0
  66. package/dist/output/HTMLDocumentRenderer.d.ts +83 -0
  67. package/dist/output/HTMLDocumentRenderer.js +717 -0
  68. package/dist/output/HTMLDocumentRenderer.js.map +1 -0
  69. package/dist/output/UIPrototypeRenderer.d.ts +61 -0
  70. package/dist/output/UIPrototypeRenderer.js +500 -0
  71. package/dist/output/UIPrototypeRenderer.js.map +1 -0
  72. package/dist/output/index.d.ts +6 -0
  73. package/dist/output/index.js +6 -0
  74. package/dist/output/index.js.map +1 -0
  75. package/dist/skills/ExternalSkills.js +2 -0
  76. package/dist/skills/ExternalSkills.js.map +1 -1
  77. package/dist/skills/SkillCatalog.d.ts +13 -0
  78. package/dist/skills/SkillCatalog.js +184 -0
  79. package/dist/skills/SkillCatalog.js.map +1 -0
  80. package/dist/skills/SkillDiscovery.js +2 -1
  81. package/dist/skills/SkillDiscovery.js.map +1 -1
  82. package/dist/skills/SkillDoctor.d.ts +37 -0
  83. package/dist/skills/SkillDoctor.js +90 -0
  84. package/dist/skills/SkillDoctor.js.map +1 -0
  85. package/dist/skills/index.d.ts +2 -0
  86. package/dist/skills/index.js +2 -0
  87. package/dist/skills/index.js.map +1 -1
  88. package/dist/skills/routing/SkillGate.d.ts +12 -0
  89. package/dist/skills/routing/SkillGate.js +93 -0
  90. package/dist/skills/routing/SkillGate.js.map +1 -0
  91. package/dist/skills/routing/SkillPlanner.d.ts +8 -0
  92. package/dist/skills/routing/SkillPlanner.js +91 -0
  93. package/dist/skills/routing/SkillPlanner.js.map +1 -0
  94. package/dist/skills/routing/SkillPolicy.d.ts +6 -0
  95. package/dist/skills/routing/SkillPolicy.js +173 -0
  96. package/dist/skills/routing/SkillPolicy.js.map +1 -0
  97. package/dist/skills/routing/SkillRoutingTypes.d.ts +72 -0
  98. package/dist/skills/routing/SkillRoutingTypes.js +2 -0
  99. package/dist/skills/routing/SkillRoutingTypes.js.map +1 -0
  100. package/dist/skills/routing/TaskIntentClassifier.d.ts +6 -0
  101. package/dist/skills/routing/TaskIntentClassifier.js +79 -0
  102. package/dist/skills/routing/TaskIntentClassifier.js.map +1 -0
  103. package/dist/skills/routing/index.d.ts +5 -0
  104. package/dist/skills/routing/index.js +6 -0
  105. package/dist/skills/routing/index.js.map +1 -0
  106. package/dist/workflow/GovernanceLock.d.ts +35 -0
  107. package/dist/workflow/GovernanceLock.js +58 -0
  108. package/dist/workflow/GovernanceLock.js.map +1 -0
  109. package/dist/workflow/GovernanceTemplatePacks.d.ts +24 -0
  110. package/dist/workflow/GovernanceTemplatePacks.js +83 -0
  111. package/dist/workflow/GovernanceTemplatePacks.js.map +1 -0
  112. package/dist/workflow/GovernanceTemplates.d.ts +17 -0
  113. package/dist/workflow/GovernanceTemplates.js +686 -0
  114. package/dist/workflow/GovernanceTemplates.js.map +1 -0
  115. package/dist/workflow/PhaseMarkerTracker.d.ts +63 -0
  116. package/dist/workflow/PhaseMarkerTracker.js +291 -0
  117. package/dist/workflow/PhaseMarkerTracker.js.map +1 -0
  118. package/dist/workflow/SessionStateTracker.d.ts +74 -0
  119. package/dist/workflow/SessionStateTracker.js +270 -0
  120. package/dist/workflow/SessionStateTracker.js.map +1 -0
  121. package/dist/workflow/TaskArtifactScaffolder.d.ts +47 -0
  122. package/dist/workflow/TaskArtifactScaffolder.js +237 -0
  123. package/dist/workflow/TaskArtifactScaffolder.js.map +1 -0
  124. package/dist/workflow/TaskMetricsStore.d.ts +49 -0
  125. package/dist/workflow/TaskMetricsStore.js +149 -0
  126. package/dist/workflow/TaskMetricsStore.js.map +1 -0
  127. package/dist/workflow/VerificationCommands.d.ts +2 -0
  128. package/dist/workflow/VerificationCommands.js +8 -12
  129. package/dist/workflow/VerificationCommands.js.map +1 -1
  130. package/dist/workflow/VerificationProfile.d.ts +56 -0
  131. package/dist/workflow/VerificationProfile.js +170 -0
  132. package/dist/workflow/VerificationProfile.js.map +1 -0
  133. package/dist/workflow/WorkflowArtifactWriter.d.ts +113 -0
  134. package/dist/workflow/WorkflowArtifactWriter.js +241 -0
  135. package/dist/workflow/WorkflowArtifactWriter.js.map +1 -0
  136. package/dist/workflow/WorkflowEngine.d.ts +26 -5
  137. package/dist/workflow/WorkflowEngine.js +38 -9
  138. package/dist/workflow/WorkflowEngine.js.map +1 -1
  139. package/dist/workflow/WorkspaceLifecycle.d.ts +51 -0
  140. package/dist/workflow/WorkspaceLifecycle.js +259 -0
  141. package/dist/workflow/WorkspaceLifecycle.js.map +1 -0
  142. package/dist/workflow/autonomous/AutonomousDevLoop.d.ts +88 -0
  143. package/dist/workflow/autonomous/AutonomousDevLoop.js +381 -0
  144. package/dist/workflow/autonomous/AutonomousDevLoop.js.map +1 -0
  145. package/dist/workflow/autonomous/WorklogManager.d.ts +50 -0
  146. package/dist/workflow/autonomous/WorklogManager.js +264 -0
  147. package/dist/workflow/autonomous/WorklogManager.js.map +1 -0
  148. package/dist/workflow/autonomous/index.d.ts +2 -0
  149. package/dist/workflow/autonomous/index.js +4 -0
  150. package/dist/workflow/autonomous/index.js.map +1 -0
  151. package/dist/workflow/gates/GateSystem.d.ts +12 -3
  152. package/dist/workflow/gates/GateSystem.js +185 -41
  153. package/dist/workflow/gates/GateSystem.js.map +1 -1
  154. package/dist/workflow/index.d.ts +10 -0
  155. package/dist/workflow/index.js +10 -0
  156. package/dist/workflow/index.js.map +1 -1
  157. package/package.json +3 -3
package/dist/api/cli.js CHANGED
@@ -12,26 +12,62 @@ import { DangerousCommandDetector, SecretLeakDetector, RoleGateDetector, ScopeCr
12
12
  import { SQLiteKnowledgeBase } from '../knowledge/SQLiteKnowledgeBase.js';
13
13
  import { ContextBuilder } from '../context/ContextBuilder.js';
14
14
  import { FSMAgentBridge } from '../fsm/FSMAgentBridge.js';
15
+ import { CapabilityRegistry } from '../capabilities/CapabilityRegistry.js';
16
+ import { SkillRegistry } from '../skills/SkillRegistry.js';
17
+ import { registerCoreSkills } from '../skills/coreSkills.js';
18
+ import { registerExternalSkills } from '../skills/ExternalSkills.js';
19
+ import { createSkillPlan, evaluateSkillGate, loadSkillRoutingPolicy, skillPlanMarkdown } from '../skills/routing/index.js';
15
20
  import { createAdapter, SUPPORTED_AGENTS } from '../adapters/index.js';
16
21
  import { LessonExtractor, RuleProposer, HookGenerator, EvolutionEngine } from '../evolution/EvolutionEngine.js';
17
22
  import { Doctor } from './doctor.js';
18
23
  import { quickStart, detectPlatform } from './quickstart.js';
19
24
  import { SkillDiscovery } from '../skills/SkillDiscovery.js';
25
+ import { inspectRequiredWorkflowSkills, inspectWorkflowSkills } from '../skills/SkillDoctor.js';
20
26
  import { listWorkflowPresets, getPresetsByScenario } from '../workflows/presets.js';
21
27
  import { EvidenceStore } from '../workflow/EvidenceStore.js';
22
28
  import { OutOfScopeStore } from '../workflow/OutOfScopeStore.js';
23
29
  import { ReviewStore } from '../workflow/ReviewStore.js';
24
- import { existsSync, mkdirSync, readFileSync } from 'node:fs';
25
- import { join } from 'node:path';
30
+ import { WorkflowEngine } from '../workflow/WorkflowEngine.js';
31
+ import { resolveVerificationTargets } from '../workflow/VerificationProfile.js';
32
+ import { writeGovernanceTemplates } from '../workflow/GovernanceTemplates.js';
33
+ import { computeGovernanceDrift } from '../workflow/GovernanceLock.js';
34
+ import { TaskMetricsStore } from '../workflow/TaskMetricsStore.js';
35
+ import { checkTaskArtifactCompleteness } from '../workflow/TaskArtifactScaffolder.js';
36
+ import { WorkflowArtifactWriter } from '../workflow/WorkflowArtifactWriter.js';
37
+ import { cleanupWorkspaceLifecycle, inspectWorkspaceLifecycle, } from '../workflow/WorkspaceLifecycle.js';
38
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
39
+ import { join, resolve } from 'node:path';
26
40
  // ============================================================================
27
41
  // Engine bootstrap (单例 + lazy init)
28
42
  // ============================================================================
29
43
  const SCALE_DIR = process.env.SCALE_DIR ?? '.scale';
44
+ const PROJECT_DIR = process.env.SCALE_PROJECT_DIR ?? process.cwd();
30
45
  const DB_PATH = join(SCALE_DIR, 'scale.db');
46
+ function governanceModeFromScenario(scenario) {
47
+ if (scenario === 'critical')
48
+ return 'critical';
49
+ if (scenario === 'sandbox')
50
+ return 'minimal';
51
+ return 'standard';
52
+ }
31
53
  function ensureDir(dir) {
32
54
  if (!existsSync(dir))
33
55
  mkdirSync(dir, { recursive: true });
34
56
  }
57
+ function isTruthyFlag(value) {
58
+ return value === true || value === '' || value === 'true' || value === '1';
59
+ }
60
+ function normalizePreflightProfile(value) {
61
+ const normalized = String(value ?? 'quick').trim().toLowerCase();
62
+ if (normalized === 'full' || normalized === 'ci')
63
+ return normalized;
64
+ return 'quick';
65
+ }
66
+ function gatesForPreflightProfile(profile) {
67
+ if (profile === 'quick')
68
+ return ['G3', 'G0', 'G4', 'G5'];
69
+ return ['G3', 'G0', 'G4', 'G5', 'G6', 'G7'];
70
+ }
35
71
  let _engine = null;
36
72
  function getEngine() {
37
73
  if (!_engine)
@@ -60,7 +96,17 @@ function createEngine() {
60
96
  const kb = new SQLiteKnowledgeBase(eventBus, { dbPath: join(SCALE_DIR, 'knowledge.db') });
61
97
  const ctx = new ContextBuilder(store, kb, eventBus);
62
98
  const fsmAgentBridge = new FSMAgentBridge(fsm, store);
63
- return { eventBus, store, fsm, gateway, roleGate, kb, ctx, fsmAgentBridge };
99
+ const capabilityRegistry = new CapabilityRegistry(eventBus);
100
+ const skillRegistry = new SkillRegistry(eventBus);
101
+ registerCoreSkills(skillRegistry);
102
+ registerExternalSkills(skillRegistry, eventBus);
103
+ const workflowEngine = new WorkflowEngine({
104
+ eventBus,
105
+ capabilityRegistry,
106
+ skillRegistry,
107
+ scaleDir: SCALE_DIR,
108
+ });
109
+ return { eventBus, store, fsm, gateway, roleGate, kb, ctx, fsmAgentBridge, workflowEngine };
64
110
  }
65
111
  // ============================================================================
66
112
  // session commands
@@ -699,6 +745,286 @@ const stats = defineCommand({
699
745
  console.log(JSON.stringify({ ...s, eventCount: events.length }, null, 2));
700
746
  },
701
747
  });
748
+ const metricsList = defineCommand({
749
+ meta: { name: 'list', description: 'List M/L task workflow metrics' },
750
+ args: {
751
+ json: { type: 'boolean', default: false },
752
+ },
753
+ async run({ args }) {
754
+ const store = new TaskMetricsStore(SCALE_DIR);
755
+ const records = store.list();
756
+ const summary = store.summarize();
757
+ if (args.json) {
758
+ console.log(JSON.stringify({ summary, records }, null, 2));
759
+ return;
760
+ }
761
+ console.log('\nWorkflow Metrics');
762
+ console.log(` Total tasks: ${summary.total}`);
763
+ console.log(` First-pass verification rate: ${(summary.firstPassRate * 100).toFixed(1)}%`);
764
+ console.log(` Average fix iterations: ${summary.averageFixIterations.toFixed(2)}`);
765
+ console.log(` Artifact completeness: ${(summary.artifactCompletenessRate * 100).toFixed(1)}%`);
766
+ for (const record of records.slice(-10)) {
767
+ console.log(` - ${record.date} ${record.level} ${record.taskName}: ${record.finalGateStatus}`);
768
+ }
769
+ },
770
+ });
771
+ const metrics = defineCommand({
772
+ meta: { name: 'metrics', description: 'Inspect workflow task metrics' },
773
+ subCommands: { list: metricsList },
774
+ });
775
+ function normalizeTaskArtifactLevel(value) {
776
+ const normalized = String(value ?? 'M').trim().toUpperCase();
777
+ if (normalized === 'S' || normalized === 'M' || normalized === 'L' || normalized === 'CRITICAL') {
778
+ return normalized;
779
+ }
780
+ throw new Error(`Invalid task level "${String(value)}"; expected S, M, L, or CRITICAL.`);
781
+ }
782
+ const taskArtifactsCheck = defineCommand({
783
+ meta: { name: 'check', description: 'Check task artifact completeness' },
784
+ args: {
785
+ dir: { type: 'string', description: 'Task artifact directory; defaults to .scale/state/current.json artifactsDir' },
786
+ level: { type: 'string', description: 'Task level: S, M, L, or CRITICAL; defaults to current state level or M' },
787
+ 'warn-only': { type: 'boolean', default: false, description: 'Return zero even when artifacts are incomplete' },
788
+ json: { type: 'boolean', default: false },
789
+ },
790
+ run({ args }) {
791
+ const state = new WorkflowArtifactWriter(SCALE_DIR).readCurrentState();
792
+ let level;
793
+ try {
794
+ level = normalizeTaskArtifactLevel(args.level ?? state?.level ?? 'M');
795
+ }
796
+ catch (e) {
797
+ console.error(e.message);
798
+ process.exit(1);
799
+ }
800
+ const result = checkTaskArtifactCompleteness({
801
+ projectDir: PROJECT_DIR,
802
+ artifactsDir: args.dir ?? state?.artifactsDir,
803
+ level,
804
+ skillRequiredArtifacts: state?.requiredSkillArtifacts,
805
+ });
806
+ if (args.json) {
807
+ console.log(JSON.stringify(result, null, 2));
808
+ }
809
+ else {
810
+ console.log(`\nTask Artifacts: ${result.complete ? 'COMPLETE' : 'INCOMPLETE'}`);
811
+ if (result.artifactsDir)
812
+ console.log(` Directory: ${result.artifactsDir}`);
813
+ console.log(` Required: ${result.required.join(', ') || 'none'}`);
814
+ for (const file of result.missing)
815
+ console.log(` [MISSING] ${file}`);
816
+ for (const item of result.incomplete)
817
+ console.log(` [INCOMPLETE] ${item.file}: ${item.reason}`);
818
+ }
819
+ if (!result.complete && !args['warn-only'])
820
+ process.exitCode = 1;
821
+ },
822
+ });
823
+ const taskArtifacts = defineCommand({
824
+ meta: { name: 'task-artifacts', description: 'Inspect task artifact completeness' },
825
+ subCommands: { check: taskArtifactsCheck },
826
+ });
827
+ function printWorkspaceLifecycle(report) {
828
+ console.log('\nSCALE Workspace Lifecycle');
829
+ console.log(` Root: ${report.root.path}`);
830
+ console.log(` Branch: ${report.root.branch ?? '(detached)'}`);
831
+ console.log(` Linked worktree: ${report.root.isLinkedWorktree ? 'yes' : 'no'}`);
832
+ console.log(` Root status: ${report.root.clean ? 'clean' : 'dirty'}`);
833
+ if (!report.root.clean) {
834
+ console.log(` staged=${report.root.staged} unstaged=${report.root.unstaged} untracked=${report.root.untracked}`);
835
+ }
836
+ if (report.childRepositories.length) {
837
+ console.log('\n Child repositories:');
838
+ for (const child of report.childRepositories) {
839
+ console.log(` ${child.clean ? '[CLEAN]' : '[DIRTY]'} ${child.relativePath} (${child.kind}) branch=${child.branch ?? '(detached)'}`);
840
+ if (!child.clean)
841
+ console.log(` staged=${child.staged} unstaged=${child.unstaged} untracked=${child.untracked}`);
842
+ }
843
+ }
844
+ else {
845
+ console.log('\n Child repositories: none');
846
+ }
847
+ console.log(`\n Cleanup candidate: ${report.finish.canCleanup ? 'yes' : 'no'}`);
848
+ for (const blocker of report.finish.blockers)
849
+ console.log(` [BLOCKER] ${blocker}`);
850
+ for (const warning of report.finish.warnings)
851
+ console.log(` [WARN] ${warning}`);
852
+ for (const action of report.finish.nextActions)
853
+ console.log(` [NEXT] ${action}`);
854
+ }
855
+ function printWorkspaceCleanup(result) {
856
+ printWorkspaceLifecycle(result.report);
857
+ console.log('\n Cleanup plan:');
858
+ console.log(` Mode: ${result.mode}`);
859
+ console.log(` Target: ${result.targetPath}`);
860
+ console.log(` Can apply: ${result.canApply ? 'yes' : 'no'}`);
861
+ console.log(` Applied: ${result.applied ? 'yes' : 'no'}`);
862
+ console.log(` Confirmation token: ${result.confirmationToken ?? '(unavailable)'}`);
863
+ for (const command of result.commands)
864
+ console.log(` Command: ${command}`);
865
+ for (const blocker of result.blockers)
866
+ console.log(` [BLOCKER] ${blocker}`);
867
+ for (const warning of result.warnings)
868
+ console.log(` [WARN] ${warning}`);
869
+ }
870
+ const workspaceStatus = defineCommand({
871
+ meta: { name: 'status', description: 'Inspect root worktree and child repository lifecycle state' },
872
+ args: {
873
+ dir: { type: 'string', description: 'Repository or worktree directory; defaults to current project directory' },
874
+ json: { type: 'boolean', default: false },
875
+ },
876
+ async run({ args }) {
877
+ const report = await inspectWorkspaceLifecycle({ projectDir: args.dir ?? PROJECT_DIR });
878
+ if (args.json) {
879
+ console.log(JSON.stringify(report, null, 2));
880
+ }
881
+ else {
882
+ printWorkspaceLifecycle(report);
883
+ }
884
+ if (report.finish.blockers.length > 0)
885
+ process.exitCode = 1;
886
+ },
887
+ });
888
+ const workspaceFinish = defineCommand({
889
+ meta: { name: 'finish', description: 'Check whether a temporary worktree can be safely finished or cleaned up' },
890
+ args: {
891
+ dir: { type: 'string', description: 'Repository or worktree directory; defaults to current project directory' },
892
+ json: { type: 'boolean', default: false },
893
+ },
894
+ async run({ args }) {
895
+ const report = await inspectWorkspaceLifecycle({ projectDir: args.dir ?? PROJECT_DIR });
896
+ const result = {
897
+ root: report.root,
898
+ childRepositories: report.childRepositories,
899
+ finish: report.finish,
900
+ };
901
+ if (args.json) {
902
+ console.log(JSON.stringify(result, null, 2));
903
+ }
904
+ else {
905
+ printWorkspaceLifecycle(report);
906
+ }
907
+ if (report.finish.blockers.length > 0)
908
+ process.exitCode = 1;
909
+ },
910
+ });
911
+ const workspaceCleanup = defineCommand({
912
+ meta: { name: 'cleanup', description: 'Dry-run or apply safe removal of a linked temporary worktree' },
913
+ args: {
914
+ dir: { type: 'string', description: 'Linked worktree directory; defaults to current project directory' },
915
+ 'dry-run': { type: 'boolean', default: false, description: 'Preview cleanup; this is the default unless --apply is set' },
916
+ apply: { type: 'boolean', default: false, description: 'Actually run git worktree remove after safety checks' },
917
+ confirm: { type: 'string', description: 'Required confirmation token for --apply, usually the worktree branch name' },
918
+ json: { type: 'boolean', default: false },
919
+ },
920
+ async run({ args }) {
921
+ const result = await cleanupWorkspaceLifecycle({
922
+ projectDir: args.dir ?? PROJECT_DIR,
923
+ apply: isTruthyFlag(args.apply),
924
+ confirm: args.confirm,
925
+ });
926
+ if (args.json) {
927
+ console.log(JSON.stringify(result, null, 2));
928
+ }
929
+ else {
930
+ printWorkspaceCleanup(result);
931
+ }
932
+ if (!result.canApply || (isTruthyFlag(args.apply) && !result.applied))
933
+ process.exitCode = 1;
934
+ },
935
+ });
936
+ const workspace = defineCommand({
937
+ meta: { name: 'workspace', description: 'Inspect worktree, branch, and child repository lifecycle safety' },
938
+ subCommands: {
939
+ status: workspaceStatus,
940
+ finish: workspaceFinish,
941
+ cleanup: workspaceCleanup,
942
+ },
943
+ });
944
+ const preflight = defineCommand({
945
+ meta: { name: 'preflight', description: 'Run service-aware verification without a task artifact' },
946
+ args: {
947
+ 'build-cmd': { type: 'string', description: 'Override build command' },
948
+ 'lint-cmd': { type: 'string', description: 'Override lint command' },
949
+ 'test-cmd': { type: 'string', description: 'Override test command' },
950
+ 'coverage-cmd': { type: 'string', description: 'Override coverage command' },
951
+ profile: { type: 'string', description: 'Verification profile from .scale/verification.json' },
952
+ 'preflight-profile': { type: 'string', default: 'quick', description: 'Gate intensity profile (quick/full/ci); quick skips coverage and security' },
953
+ service: { type: 'string', description: 'Service name from .scale/verification.json; use all for required services' },
954
+ 'tdd-evidence': { type: 'string', description: 'Path to JSON TDD evidence with red/green/refactor/testFirst=true' },
955
+ 'tdd-strict': { type: 'boolean', default: false, description: 'Require TDD evidence before other gates' },
956
+ json: { type: 'boolean', default: false },
957
+ },
958
+ async run({ args }) {
959
+ const { workflowEngine } = getEngine();
960
+ const preflightProfile = normalizePreflightProfile(args['preflight-profile']);
961
+ const gateStages = gatesForPreflightProfile(preflightProfile);
962
+ const resolved = resolveVerificationTargets({
963
+ projectDir: PROJECT_DIR,
964
+ scaleDir: SCALE_DIR,
965
+ profile: args.profile,
966
+ service: args.service,
967
+ });
968
+ const targetResults = [];
969
+ if (!args.json) {
970
+ console.log('\nSCALE Preflight');
971
+ for (const warning of resolved.warnings)
972
+ console.log(` [WARN] ${warning}`);
973
+ console.log(` Profile: ${resolved.profileName}`);
974
+ console.log(` Preflight profile: ${preflightProfile}`);
975
+ console.log(` Gates: ${gateStages.join(', ')}`);
976
+ }
977
+ for (const target of resolved.targets) {
978
+ if (!args.json) {
979
+ const label = target.service ? `${target.service.name} (${target.service.path})` : 'root';
980
+ console.log(`\n Target: ${label}`);
981
+ }
982
+ const gates = await workflowEngine.verify({
983
+ cwd: target.config.cwd,
984
+ build: args['build-cmd'] ?? target.config.build,
985
+ lint: args['lint-cmd'] ?? target.config.lint,
986
+ test: args['test-cmd'] ?? target.config.test,
987
+ coverage: args['coverage-cmd'] ?? target.config.coverage,
988
+ tddEvidence: args['tdd-evidence'],
989
+ tddStrict: isTruthyFlag(args['tdd-strict']),
990
+ gates: gateStages,
991
+ });
992
+ const passed = gates.every(gate => gate.passed);
993
+ targetResults.push({
994
+ service: target.service?.name,
995
+ cwd: target.config.cwd ?? PROJECT_DIR,
996
+ gates,
997
+ passed,
998
+ });
999
+ if (!args.json) {
1000
+ for (const gate of gates) {
1001
+ console.log(` ${gate.passed ? '[PASS]' : '[FAIL]'} ${gate.gate}: ${gate.evidence.slice(0, 80)}`);
1002
+ for (const blocker of gate.blockers)
1003
+ console.log(` [BLOCKER] ${blocker.slice(0, 120)}`);
1004
+ }
1005
+ }
1006
+ }
1007
+ const passed = targetResults.length > 0 && targetResults.every(target => target.passed);
1008
+ const result = {
1009
+ phase: 'PREFLIGHT',
1010
+ profile: resolved.profileName,
1011
+ preflightProfile,
1012
+ gates: gateStages,
1013
+ services: targetResults.map(target => target.service).filter(Boolean),
1014
+ policy: resolved.policy,
1015
+ targets: targetResults,
1016
+ passed,
1017
+ };
1018
+ if (args.json) {
1019
+ console.log(JSON.stringify(result, null, 2));
1020
+ }
1021
+ else {
1022
+ console.log(`\nPREFLIGHT: ${passed ? 'PASSED' : 'FAILED'}\n`);
1023
+ }
1024
+ if (!passed)
1025
+ process.exitCode = 1;
1026
+ },
1027
+ });
702
1028
  const status = defineCommand({
703
1029
  meta: { name: 'status', description: 'Show current SCALE workflow status' },
704
1030
  args: {
@@ -819,13 +1145,116 @@ const init = defineCommand({
819
1145
  args: {
820
1146
  agent: { type: 'string', default: '', description: `Agent type (${SUPPORTED_AGENTS.join('/')}) - auto-detected if not specified` },
821
1147
  dir: { type: 'string', default: '.', description: 'Project directory' },
1148
+ json: { type: 'boolean', default: false, description: 'Output initialization result as JSON' },
822
1149
  scenario: { type: 'string', default: 'standard', description: 'Scenario mode (sandbox/standard/critical)' },
1150
+ 'governance-pack': {
1151
+ type: 'string',
1152
+ default: 'standard',
1153
+ description: 'Governance template pack (standard/project-scaffold/go-service-matrix/node-library/frontend-app)',
1154
+ },
823
1155
  quick: { type: 'boolean', default: false, description: 'Quick start with auto-detection' },
1156
+ interactive: { type: 'boolean', default: false, description: 'Interactive configuration mode with prompts' },
1157
+ 'coverage-threshold': { type: 'string', default: '80', description: 'Coverage threshold (default 80%)' },
1158
+ 'retry-threshold': { type: 'string', default: '3', description: 'Brute retry threshold (default 3)' },
1159
+ 'block-severity': { type: 'string', default: 'CRITICAL', description: 'Block severity level (CRITICAL/HIGH/MEDIUM)' },
824
1160
  },
825
1161
  async run({ args }) {
1162
+ // Interactive configuration mode
1163
+ if (args.interactive) {
1164
+ console.log('\n🔧 SCALE Engine Interactive Configuration\n');
1165
+ console.log('='.repeat(50));
1166
+ // Step 1: Detect and suggest agent platform
1167
+ const detection = detectPlatform(args.dir);
1168
+ console.log('\n📋 Step 1: Agent Platform Selection');
1169
+ console.log(` Detected suggestions: ${detection.suggestions.join(', ') || 'none'}`);
1170
+ const agentType = args.agent || detection.suggestions[0] || 'claude-code';
1171
+ console.log(` Using: ${agentType}`);
1172
+ // Step 2: Scenario mode
1173
+ console.log('\n📋 Step 2: Scenario Mode');
1174
+ console.log(' sandbox - No quality gates (POC/prototype)');
1175
+ console.log(' standard - Default quality gates');
1176
+ console.log(' critical - Hardened gates + manual approval');
1177
+ const scenarioMode = args.scenario;
1178
+ console.log(` Using: ${scenarioMode}`);
1179
+ // Step 3: Quality Gate Thresholds (quantified)
1180
+ console.log('\n📋 Step 3: Quality Gate Thresholds');
1181
+ const coverageThreshold = parseInt(args['coverage-threshold'], 10) || 80;
1182
+ const retryThreshold = parseInt(args['retry-threshold'], 10) || 3;
1183
+ const blockSeverity = args['block-severity'] || 'CRITICAL';
1184
+ console.log(` Coverage threshold: ${coverageThreshold}%`);
1185
+ console.log(` Retry threshold: ${retryThreshold} (brute retry block)`);
1186
+ console.log(` Block severity: ${blockSeverity}`);
1187
+ // Step 4: Write thresholds to .scale/thresholds.json
1188
+ const thresholdsPath = join(args.dir, '.scale', 'thresholds.json');
1189
+ ensureDir(join(args.dir, '.scale'));
1190
+ writeFileSync(thresholdsPath, JSON.stringify({
1191
+ coverage: { minimum: coverageThreshold, unit: 'percent' },
1192
+ retry: { bruteMaximum: retryThreshold, unit: 'count' },
1193
+ severity: { blockLevel: blockSeverity },
1194
+ gates: {
1195
+ G3_build: { required: scenarioMode !== 'sandbox', exitCode: 0 },
1196
+ G4_lint: { required: scenarioMode !== 'sandbox', exitCode: 0 },
1197
+ G5_tests: { required: scenarioMode !== 'sandbox', allPass: true },
1198
+ G6_coverage: { required: scenarioMode !== 'sandbox', minimum: coverageThreshold },
1199
+ G7_security: { required: scenarioMode === 'critical', noCritical: true },
1200
+ },
1201
+ }, null, 2));
1202
+ console.log(`\n ✓ Thresholds written to: ${thresholdsPath}`);
1203
+ // Initialize with adapter
1204
+ const adapter = createAdapter(agentType);
1205
+ const result = await adapter.init({
1206
+ projectDir: args.dir,
1207
+ agentType: agentType,
1208
+ scenarioMode,
1209
+ thresholdsPath,
1210
+ });
1211
+ const projectName = args.dir.split(/[/\\]/).pop() || 'Project';
1212
+ const governance = writeGovernanceTemplates(args.dir, {
1213
+ mode: governanceModeFromScenario(scenarioMode),
1214
+ projectName,
1215
+ pack: args['governance-pack'],
1216
+ });
1217
+ result.created.push(...governance.created);
1218
+ result.skipped.push(...governance.skipped);
1219
+ console.log(`\n✅ SCALE Engine initialized for ${agentType} (interactive mode)`);
1220
+ console.log(`\n📁 Created:`);
1221
+ for (const f of result.created)
1222
+ console.log(` + ${f}`);
1223
+ if (result.skipped.length > 0) {
1224
+ console.log(`\n⏭️ Skipped (already exist):`);
1225
+ for (const f of result.skipped)
1226
+ console.log(` - ${f}`);
1227
+ }
1228
+ console.log(`\n🔧 Configuration Summary:`);
1229
+ console.log(` Settings: ${result.settingsPath}`);
1230
+ console.log(` Knowledge: ${result.knowledgeDocPath}`);
1231
+ console.log(` Thresholds: ${thresholdsPath}`);
1232
+ console.log(` Data dir: ${result.scaleDir}`);
1233
+ console.log(` Scenario: ${scenarioMode}`);
1234
+ console.log(`\n📋 Next steps:`);
1235
+ console.log(` → scale doctor`);
1236
+ console.log(` → scale create Spec "<feature name>"`);
1237
+ return;
1238
+ }
826
1239
  // One-click quick start mode
827
- if (args.quick || !args.agent) {
828
- const qsResult = await quickStart(args.dir);
1240
+ if (!args.agent) {
1241
+ const qsResult = await quickStart(args.dir, { governancePack: args['governance-pack'] });
1242
+ if (args.json) {
1243
+ const detection = qsResult.success ? undefined : detectPlatform(args.dir);
1244
+ console.log(JSON.stringify({
1245
+ ok: qsResult.success,
1246
+ mode: 'quick',
1247
+ platform: qsResult.platform,
1248
+ created: qsResult.created,
1249
+ skipped: qsResult.skipped,
1250
+ constraintsApplied: qsResult.constraintsApplied,
1251
+ capabilitiesEnabled: qsResult.capabilitiesEnabled,
1252
+ knowledgeGraph: qsResult.knowledgeGraph,
1253
+ nextSteps: qsResult.nextSteps,
1254
+ suggestions: detection?.suggestions ?? [],
1255
+ }, null, 2));
1256
+ return;
1257
+ }
829
1258
  if (qsResult.success && qsResult.platform) {
830
1259
  console.log(`\n✅ SCALE Engine Quick Start completed for ${qsResult.platform}`);
831
1260
  console.log(`\n📁 Created (${qsResult.created.length}):`);
@@ -853,6 +1282,30 @@ const init = defineCommand({
853
1282
  // Manual agent specification mode
854
1283
  const adapter = createAdapter(args.agent);
855
1284
  const result = await adapter.init({ projectDir: args.dir, agentType: args.agent, scenarioMode: args.scenario });
1285
+ const projectName = args.dir.split(/[/\\]/).pop() || 'Project';
1286
+ const governance = writeGovernanceTemplates(args.dir, {
1287
+ mode: governanceModeFromScenario(args.scenario),
1288
+ projectName,
1289
+ pack: args['governance-pack'],
1290
+ });
1291
+ result.created.push(...governance.created);
1292
+ result.skipped.push(...governance.skipped);
1293
+ if (args.json) {
1294
+ console.log(JSON.stringify({
1295
+ ok: true,
1296
+ mode: args.quick ? 'quick-agent' : 'manual',
1297
+ agent: args.agent,
1298
+ scenario: args.scenario,
1299
+ governancePack: args['governance-pack'],
1300
+ settingsPath: result.settingsPath,
1301
+ knowledgeDocPath: result.knowledgeDocPath,
1302
+ scaleDir: result.scaleDir,
1303
+ created: result.created,
1304
+ skipped: result.skipped,
1305
+ nextSteps: ['scale doctor', 'scale create Spec "<feature name>"'],
1306
+ }, null, 2));
1307
+ return;
1308
+ }
856
1309
  console.log(`\n✅ SCALE Engine initialized for ${args.agent} (scenario: ${args.scenario})`);
857
1310
  console.log(`\n📁 Created:`);
858
1311
  for (const f of result.created)
@@ -871,6 +1324,39 @@ const init = defineCommand({
871
1324
  },
872
1325
  });
873
1326
  // ============================================================================
1327
+ // governance command — Generated governance asset tooling
1328
+ // ============================================================================
1329
+ const governanceDiff = defineCommand({
1330
+ meta: { name: 'diff', description: 'Check generated governance files for drift' },
1331
+ args: {
1332
+ dir: { type: 'string', default: '.', description: 'Project directory' },
1333
+ json: { type: 'boolean', default: false, description: 'Print JSON output' },
1334
+ },
1335
+ run({ args }) {
1336
+ const report = computeGovernanceDrift(args.dir);
1337
+ if (args.json) {
1338
+ console.log(JSON.stringify(report, null, 2));
1339
+ return;
1340
+ }
1341
+ if (!report.lockExists) {
1342
+ console.log('No governance lock found. Run: scale init --governance-pack <pack>');
1343
+ return;
1344
+ }
1345
+ if (report.missing.length === 0 && report.changed.length === 0) {
1346
+ console.log('Governance generated files are clean.');
1347
+ return;
1348
+ }
1349
+ for (const item of report.missing)
1350
+ console.log(`missing: ${item.path}`);
1351
+ for (const item of report.changed)
1352
+ console.log(`changed: ${item.path}`);
1353
+ },
1354
+ });
1355
+ const governance = defineCommand({
1356
+ meta: { name: 'governance', description: 'Governance template pack tools' },
1357
+ subCommands: { diff: governanceDiff },
1358
+ });
1359
+ // ============================================================================
874
1360
  // evolve command
875
1361
  // ============================================================================
876
1362
  const evolve = defineCommand({
@@ -914,11 +1400,29 @@ const workflowList = defineCommand({
914
1400
  meta: { name: 'list', description: 'List all workflow presets' },
915
1401
  args: {
916
1402
  scenario: { type: 'string', description: 'Filter by scenario mode (sandbox/standard/critical)' },
1403
+ json: { type: 'boolean', default: false, description: 'Output workflow presets as JSON' },
917
1404
  },
918
1405
  async run({ args }) {
919
1406
  const presets = args.scenario
920
1407
  ? getPresetsByScenario(args.scenario)
921
1408
  : listWorkflowPresets();
1409
+ if (args.json) {
1410
+ console.log(JSON.stringify({
1411
+ ok: true,
1412
+ scenario: args.scenario ?? null,
1413
+ count: presets.length,
1414
+ presets: presets.map(preset => ({
1415
+ id: preset.id,
1416
+ name: preset.name,
1417
+ nameZh: preset.nameZh,
1418
+ description: preset.description,
1419
+ scenarioMode: preset.scenarioMode,
1420
+ requiredArtifacts: preset.requiredArtifacts,
1421
+ steps: preset.steps,
1422
+ })),
1423
+ }, null, 2));
1424
+ return;
1425
+ }
922
1426
  if (presets.length === 0) {
923
1427
  console.log('No workflow presets found.');
924
1428
  return;
@@ -1092,15 +1596,34 @@ const skillScan = defineCommand({
1092
1596
  meta: { name: 'scan', description: 'Scan for installed skills' },
1093
1597
  args: {
1094
1598
  dir: { type: 'string', default: '.', description: 'Project directory' },
1599
+ json: { type: 'boolean', default: false, description: 'Output scan result as JSON' },
1095
1600
  },
1096
1601
  async run({ args }) {
1097
1602
  const discovery = new SkillDiscovery(args.dir);
1098
1603
  const platform = discovery.detectPlatform();
1604
+ if (!platform && args.json) {
1605
+ console.log(JSON.stringify({
1606
+ ok: false,
1607
+ platform: null,
1608
+ skills: [],
1609
+ message: 'No agent platform detected. Run `scale init` first.',
1610
+ }, null, 2));
1611
+ return;
1612
+ }
1099
1613
  if (!platform) {
1100
1614
  console.log('\n⚠️ No agent platform detected. Run `scale init` first.');
1101
1615
  return;
1102
1616
  }
1103
1617
  const result = discovery.scanSkills(platform);
1618
+ if (args.json) {
1619
+ console.log(JSON.stringify({
1620
+ ok: true,
1621
+ platform: result.platform,
1622
+ count: result.skills.length,
1623
+ skills: result.skills,
1624
+ }, null, 2));
1625
+ return;
1626
+ }
1104
1627
  console.log(`\n🔍 Platform: ${result.platform}`);
1105
1628
  console.log(`📦 Skills found: ${result.skills.length}`);
1106
1629
  if (result.skills.length > 0) {
@@ -1115,18 +1638,170 @@ const skillScan = defineCommand({
1115
1638
  }
1116
1639
  },
1117
1640
  });
1641
+ const skillPlanCommand = defineCommand({
1642
+ meta: { name: 'plan', description: 'Create or refresh a task skill plan' },
1643
+ args: {
1644
+ 'task-id': { type: 'positional', required: true },
1645
+ dir: { type: 'string', description: 'Task artifact directory; defaults to current state artifactsDir' },
1646
+ json: { type: 'boolean', default: false },
1647
+ },
1648
+ async run({ args }) {
1649
+ const { store } = getEngine();
1650
+ const task = await store.get(args['task-id']);
1651
+ if (!task || task.type !== 'Task') {
1652
+ console.error(`Task not found: ${args['task-id']}`);
1653
+ process.exit(1);
1654
+ }
1655
+ const payload = task.payload;
1656
+ const level = normalizeTaskArtifactLevel(payload.workflowLevel ?? 'M');
1657
+ const policy = loadSkillRoutingPolicy(PROJECT_DIR, SCALE_DIR);
1658
+ const plan = createSkillPlan({
1659
+ taskId: task.id,
1660
+ taskName: task.title,
1661
+ description: payload.description,
1662
+ level,
1663
+ services: payload.servicesTouched ?? [],
1664
+ files: payload.filesInvolved ?? [],
1665
+ policy,
1666
+ });
1667
+ const updatedPayload = {
1668
+ ...payload,
1669
+ skillIntents: plan.intents.map(intent => intent.domain),
1670
+ skillRoutingMode: plan.mode,
1671
+ skillPlanRequired: plan.required,
1672
+ requiredSkills: plan.requiredSkills,
1673
+ recommendedSkills: plan.recommendedSkills,
1674
+ requiredSkillArtifacts: plan.requiredArtifacts,
1675
+ requiredSkillVerification: plan.requiredVerification,
1676
+ };
1677
+ await store.update(task.id, { payload: updatedPayload });
1678
+ const state = new WorkflowArtifactWriter(SCALE_DIR).readCurrentState();
1679
+ const artifactsDir = args.dir ?? (state?.taskId === task.id ? state.artifactsDir : undefined);
1680
+ let writtenPath;
1681
+ if (artifactsDir) {
1682
+ const dir = resolve(PROJECT_DIR, artifactsDir);
1683
+ ensureDir(dir);
1684
+ writtenPath = join(dir, 'skill-plan.md');
1685
+ writeFileSync(writtenPath, skillPlanMarkdown(plan), 'utf-8');
1686
+ }
1687
+ new WorkflowArtifactWriter(SCALE_DIR).updateCurrentState({
1688
+ taskId: task.id,
1689
+ level,
1690
+ phase: 'plan',
1691
+ artifactsDir,
1692
+ skillIntents: plan.intents.map(intent => intent.domain),
1693
+ skillRoutingMode: plan.mode,
1694
+ skillPlanRequired: plan.required,
1695
+ skillPlanPath: writtenPath,
1696
+ requiredSkills: plan.requiredSkills,
1697
+ recommendedSkills: plan.recommendedSkills,
1698
+ requiredSkillArtifacts: plan.requiredArtifacts,
1699
+ requiredSkillVerification: plan.requiredVerification,
1700
+ });
1701
+ if (args.json) {
1702
+ console.log(JSON.stringify({ plan, writtenPath }, null, 2));
1703
+ return;
1704
+ }
1705
+ console.log('\nSkill Plan');
1706
+ console.log(` Task: ${task.id}`);
1707
+ console.log(` Intents: ${plan.intents.map(intent => intent.domain).join(', ') || 'none'}`);
1708
+ console.log(` Required skills: ${plan.requiredSkills.join(', ') || 'none'}`);
1709
+ console.log(` Recommended skills: ${plan.recommendedSkills.join(', ') || 'none'}`);
1710
+ console.log(` Required artifacts: ${plan.requiredArtifacts.join(', ') || 'none'}`);
1711
+ if (writtenPath)
1712
+ console.log(` Written: ${writtenPath}`);
1713
+ },
1714
+ });
1715
+ const skillDoctorCommand = defineCommand({
1716
+ meta: { name: 'doctor', description: 'Check workflow skill installation status' },
1717
+ args: {
1718
+ dir: { type: 'string', default: '.', description: 'Project directory' },
1719
+ json: { type: 'boolean', default: false, description: 'Output skill doctor report as JSON' },
1720
+ },
1721
+ run({ args }) {
1722
+ const report = inspectWorkflowSkills({ projectDir: args.dir });
1723
+ if (args.json) {
1724
+ console.log(JSON.stringify(report, null, 2));
1725
+ return;
1726
+ }
1727
+ console.log('\nSCALE Skill Doctor');
1728
+ console.log(` Installed: ${report.installed}/${report.total}`);
1729
+ for (const skill of report.skills) {
1730
+ console.log(` ${skill.installed ? '[OK]' : '[MISSING]'} ${skill.id}`);
1731
+ if (skill.detectedPath)
1732
+ console.log(` path: ${skill.detectedPath}`);
1733
+ if (!skill.installed)
1734
+ console.log(` install: ${skill.installCommand}`);
1735
+ }
1736
+ if (!report.ok)
1737
+ process.exitCode = 1;
1738
+ },
1739
+ });
1740
+ const skillCheckCommand = defineCommand({
1741
+ meta: { name: 'check', description: 'Check required skill evidence artifacts' },
1742
+ args: {
1743
+ dir: { type: 'string', description: 'Task artifact directory; defaults to current state artifactsDir' },
1744
+ level: { type: 'string', description: 'Task level: S, M, L, or CRITICAL; defaults to current state level or M' },
1745
+ 'require-installed': { type: 'boolean', default: false, description: 'Fail when required workflow skills are not installed locally' },
1746
+ json: { type: 'boolean', default: false },
1747
+ },
1748
+ run({ args }) {
1749
+ const state = new WorkflowArtifactWriter(SCALE_DIR).readCurrentState();
1750
+ const level = normalizeTaskArtifactLevel(args.level ?? state?.level ?? 'M');
1751
+ const policy = loadSkillRoutingPolicy(PROJECT_DIR, SCALE_DIR);
1752
+ const result = evaluateSkillGate({
1753
+ projectDir: PROJECT_DIR,
1754
+ artifactsDir: args.dir ?? state?.artifactsDir,
1755
+ level,
1756
+ requiredArtifacts: state?.requiredSkillArtifacts,
1757
+ mode: state?.skillRoutingMode ?? policy.policy.mode,
1758
+ enforceLevels: policy.policy.enforceLevels,
1759
+ });
1760
+ const skillInstallation = inspectRequiredWorkflowSkills(state?.requiredSkills ?? [], { projectDir: PROJECT_DIR });
1761
+ const requireInstalled = isTruthyFlag(args['require-installed']);
1762
+ const blocked = result.blocked || (requireInstalled && !skillInstallation.ok);
1763
+ const output = {
1764
+ ...result,
1765
+ complete: result.complete && (!requireInstalled || skillInstallation.ok),
1766
+ blocked,
1767
+ skillInstallation: {
1768
+ ...skillInstallation,
1769
+ checked: requireInstalled,
1770
+ },
1771
+ };
1772
+ if (args.json) {
1773
+ console.log(JSON.stringify(output, null, 2));
1774
+ return;
1775
+ }
1776
+ console.log(`\nSkill Gate: ${output.complete ? 'COMPLETE' : 'INCOMPLETE'}`);
1777
+ console.log(` Mode: ${output.mode}`);
1778
+ console.log(` Required artifacts: ${output.required.join(', ') || 'none'}`);
1779
+ console.log(` Required skills: ${skillInstallation.required.join(', ') || 'none'}`);
1780
+ for (const file of output.missing)
1781
+ console.log(` [MISSING] ${file}`);
1782
+ for (const item of output.incomplete)
1783
+ console.log(` [INCOMPLETE] ${item.file}: ${item.reason}`);
1784
+ if (requireInstalled && !skillInstallation.ok) {
1785
+ for (const skill of skillInstallation.skills.filter(skill => !skill.installed)) {
1786
+ console.log(` [MISSING_SKILL] ${skill.id}: ${skill.installCommand}`);
1787
+ }
1788
+ for (const skill of skillInstallation.unknown)
1789
+ console.log(` [UNKNOWN_SKILL] ${skill}`);
1790
+ }
1791
+ if (blocked)
1792
+ process.exitCode = 1;
1793
+ },
1794
+ });
1118
1795
  const skill = defineCommand({
1119
1796
  meta: { name: 'skill', description: 'Skill discovery and management' },
1120
- subCommands: { scan: skillScan },
1797
+ subCommands: { scan: skillScan, doctor: skillDoctorCommand, plan: skillPlanCommand, check: skillCheckCommand },
1121
1798
  });
1122
1799
  // ============================================================================
1123
1800
  // agent commands — Multi-Agent 协作系统 (Phase 9)
1124
1801
  // ============================================================================
1125
1802
  import { AgentPool } from '../agents/AgentPool.js';
1126
- import { AgentChannel } from '../agents/AgentChannel.js';
1127
1803
  import { PROFESSIONAL_AGENTS, getProfile, listProfiles } from '../agents/profiles.js';
1128
1804
  const agentPool = new AgentPool();
1129
- const agentChannel = new AgentChannel(getEngine().eventBus);
1130
1805
  const agentSpawn = defineCommand({
1131
1806
  meta: { name: 'spawn', description: 'Spawn a new agent instance' },
1132
1807
  args: {
@@ -1244,7 +1919,7 @@ import * as phaseCommands from '../cli/phaseCommands.js';
1244
1919
  import * as liteCommands from '../cli/liteCommands.js';
1245
1920
  import * as vibeCommands from '../cli/vibeCommands.js';
1246
1921
  const main = defineCommand({
1247
- meta: { name: 'scale', version: '0.12.2', description: 'SCALE Engine v0.12.2 CLI - hardened phase workflow gates: define/plan/build/verify/review/ship; Vibe templates: scale vibe; 16 platform adapters; 12 agents; 10 workflows; 19 detectors' },
1922
+ 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' },
1248
1923
  subCommands: {
1249
1924
  // Lite Mode (agent-skills style interactive entry)
1250
1925
  lite: liteCommands.liteCommand,
@@ -1274,10 +1949,16 @@ const main = defineCommand({
1274
1949
  context,
1275
1950
  evolve,
1276
1951
  stats,
1952
+ preflight,
1953
+ governance,
1954
+ metrics,
1955
+ 'task-artifacts': taskArtifacts,
1956
+ workspace,
1277
1957
  status,
1278
1958
  workflow,
1279
1959
  evidence,
1280
1960
  skill,
1961
+ skills: skill,
1281
1962
  agent,
1282
1963
  team,
1283
1964
  'create-prd': createPRD,