@polymorphism-tech/morph-spec 4.2.0 → 4.3.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 (132) hide show
  1. package/bin/morph-spec.js +283 -8
  2. package/bin/validate.js +4 -4
  3. package/docs/{v3.0 → next-generation}/AGENTS.md +1 -1
  4. package/docs/next-generation/CONTEXT-OPTIMIZATION.md +267 -0
  5. package/docs/next-generation/EXECUTION-FLOW.md +274 -0
  6. package/docs/next-generation/META-PROMPTS.md +235 -0
  7. package/docs/next-generation/MIGRATION-GUIDE.md +253 -0
  8. package/docs/next-generation/THREAD-MANAGEMENT.md +240 -0
  9. package/package.json +5 -5
  10. package/src/commands/agents/agents-fuse.js +96 -0
  11. package/src/commands/agents/micro-agent.js +112 -0
  12. package/src/commands/agents/spawn-team.js +69 -4
  13. package/src/commands/agents/squad-template.js +146 -0
  14. package/src/commands/analytics/analytics.js +176 -0
  15. package/src/commands/context/context-prime.js +63 -0
  16. package/src/commands/context/core-four.js +54 -0
  17. package/src/commands/mcp/mcp.js +102 -0
  18. package/src/commands/project/detect-agents.js +1 -1
  19. package/src/commands/project/doctor.js +573 -356
  20. package/src/commands/project/init.js +1 -1
  21. package/src/commands/project/update.js +1 -1
  22. package/src/commands/state/advance-phase.js +433 -416
  23. package/src/commands/templates/template-render.js +80 -1
  24. package/src/commands/threads/thread-template.js +103 -0
  25. package/src/commands/threads/threads.js +261 -0
  26. package/src/commands/trust/trust.js +205 -0
  27. package/src/{orchestrator.js → core/orchestrator.js} +8 -8
  28. package/src/core/state/state-manager.js +18 -2
  29. package/src/core/workflows/workflow-detector.js +100 -2
  30. package/src/lib/agents/micro-agent-factory.js +161 -0
  31. package/src/lib/analytics/analytics-engine.js +345 -0
  32. package/src/lib/checkpoints/checkpoint-hooks.js +293 -258
  33. package/src/lib/context/context-bundler.js +240 -0
  34. package/src/lib/context/context-optimizer.js +212 -0
  35. package/src/lib/context/context-tracker.js +273 -0
  36. package/src/lib/context/core-four-tracker.js +201 -0
  37. package/src/lib/context/mcp-optimizer.js +200 -0
  38. package/src/lib/execution/fusion-executor.js +304 -0
  39. package/src/lib/execution/parallel-executor.js +270 -0
  40. package/src/lib/generators/context-generator.js +3 -3
  41. package/src/lib/generators/recap-generator.js +2 -2
  42. package/src/lib/hooks/hook-executor.js +169 -0
  43. package/src/lib/hooks/stop-hook-executor.js +286 -0
  44. package/src/lib/hops/hop-composer.js +221 -0
  45. package/src/lib/threads/thread-coordinator.js +238 -0
  46. package/src/lib/threads/thread-manager.js +317 -0
  47. package/src/lib/tracking/artifact-trail.js +202 -0
  48. package/src/lib/trust/trust-manager.js +269 -0
  49. package/src/lib/validators/design-system/design-system-validator.js +2 -2
  50. package/src/lib/validators/validation-runner.js +6 -6
  51. package/stacks/blazor-azure/.morph/config/agents.json +72 -3
  52. package/stacks/nextjs-supabase/.morph/config/agents.json +3 -3
  53. package/CLAUDE.md +0 -993
  54. package/docs/llm-interaction-config.md +0 -735
  55. package/docs/v3.0/EXECUTION-FLOW.md +0 -1304
  56. package/src/commands/utils/migrate-state.js +0 -158
  57. package/src/commands/utils/upgrade.js +0 -346
  58. package/src/lib/validators/architecture-validator.js +0 -60
  59. package/src/lib/validators/content-validator.js +0 -164
  60. package/src/lib/validators/package-validator.js +0 -61
  61. package/src/lib/validators/ui-contrast-validator.js +0 -44
  62. package/stacks/blazor-azure/.claude/commands/morph-apply.md +0 -221
  63. package/stacks/blazor-azure/.claude/commands/morph-archive.md +0 -79
  64. package/stacks/blazor-azure/.claude/commands/morph-deploy.md +0 -529
  65. package/stacks/blazor-azure/.claude/commands/morph-infra.md +0 -209
  66. package/stacks/blazor-azure/.claude/commands/morph-preflight.md +0 -227
  67. package/stacks/blazor-azure/.claude/commands/morph-proposal.md +0 -122
  68. package/stacks/blazor-azure/.claude/commands/morph-status.md +0 -86
  69. package/stacks/blazor-azure/.claude/commands/morph-troubleshoot.md +0 -122
  70. package/stacks/blazor-azure/.claude/skills/level-0-meta/README.md +0 -7
  71. package/stacks/blazor-azure/.claude/skills/level-0-meta/code-review.md +0 -226
  72. package/stacks/blazor-azure/.claude/skills/level-0-meta/morph-checklist.md +0 -117
  73. package/stacks/blazor-azure/.claude/skills/level-0-meta/simulation-checklist.md +0 -77
  74. package/stacks/blazor-azure/.claude/skills/level-1-workflows/README.md +0 -7
  75. package/stacks/blazor-azure/.claude/skills/level-1-workflows/morph-replicate.md +0 -213
  76. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-clarify.md +0 -131
  77. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-design.md +0 -213
  78. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-setup.md +0 -106
  79. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-tasks.md +0 -164
  80. package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-uiux.md +0 -169
  81. package/stacks/blazor-azure/.claude/skills/level-2-domains/README.md +0 -14
  82. package/stacks/blazor-azure/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -192
  83. package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -197
  84. package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/prompt-engineer.md +0 -189
  85. package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/seo-growth-hacker.md +0 -320
  86. package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -156
  87. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/api-designer.md +0 -59
  88. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -77
  89. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -58
  90. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -126
  91. package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -45
  92. package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -210
  93. package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -154
  94. package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -191
  95. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -142
  96. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +0 -699
  97. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -126
  98. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -131
  99. package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -119
  100. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -130
  101. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -142
  102. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -108
  103. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/hangfire-orchestrator.md +0 -64
  104. package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/resend-email.md +0 -119
  105. package/stacks/blazor-azure/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -235
  106. package/stacks/blazor-azure/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -126
  107. package/stacks/blazor-azure/.claude/skills/level-3-technologies/README.md +0 -7
  108. package/stacks/blazor-azure/.claude/skills/level-4-patterns/README.md +0 -7
  109. package/stacks/blazor-azure/.morph/archive/.gitkeep +0 -25
  110. package/stacks/blazor-azure/.morph/features/.gitkeep +0 -25
  111. package/stacks/blazor-azure/.morph/schemas/agent.schema.json +0 -296
  112. package/stacks/blazor-azure/.morph/schemas/tasks.schema.json +0 -220
  113. package/stacks/blazor-azure/.morph/specs/.gitkeep +0 -20
  114. package/stacks/blazor-azure/.morph/test-infra/example.bicep +0 -59
  115. package/stacks/nextjs-supabase/.claude/commands/morph-apply.md +0 -221
  116. package/stacks/nextjs-supabase/.claude/commands/morph-archive.md +0 -79
  117. package/stacks/nextjs-supabase/.claude/commands/morph-deploy.md +0 -529
  118. package/stacks/nextjs-supabase/.claude/commands/morph-infra.md +0 -209
  119. package/stacks/nextjs-supabase/.claude/commands/morph-preflight.md +0 -227
  120. package/stacks/nextjs-supabase/.claude/commands/morph-proposal.md +0 -122
  121. package/stacks/nextjs-supabase/.claude/commands/morph-status.md +0 -86
  122. package/stacks/nextjs-supabase/.claude/commands/morph-troubleshoot.md +0 -122
  123. package/stacks/nextjs-supabase/.claude/settings.local.json +0 -6
  124. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +0 -244
  125. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +0 -335
  126. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +0 -189
  127. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +0 -50
  128. /package/docs/{v3.0 → next-generation}/ANALYSIS.md +0 -0
  129. /package/docs/{v3.0 → next-generation}/ARCHITECTURE.md +0 -0
  130. /package/docs/{v3.0 → next-generation}/FEATURES.md +0 -0
  131. /package/docs/{v3.0 → next-generation}/README.md +0 -0
  132. /package/docs/{v3.0 → next-generation}/ROADMAP.md +0 -0
@@ -3,11 +3,90 @@
3
3
  */
4
4
 
5
5
  import { writeFileSync, mkdirSync } from 'fs';
6
- import { dirname } from 'path';
6
+ import { dirname, join } from 'path';
7
7
  import chalk from 'chalk';
8
8
  import { logger } from '../../utils/logger.js';
9
9
  import { getTemplateById, resolveTemplatePathById } from '../../core/templates/template-registry.js';
10
10
  import { renderTemplate } from '../../core/templates/template-renderer.js';
11
+ import { renderHOP, listAvailableHOPs } from '../../lib/hops/hop-composer.js';
12
+
13
+ /**
14
+ * Render HOP (Higher-Order Prompt) template command
15
+ */
16
+ export async function hopRenderCommand(hopId, outputPath, variablesJson, options) {
17
+ logger.header(`Rendering HOP: ${hopId}`);
18
+ logger.blank();
19
+
20
+ try {
21
+ // Parse variables
22
+ let variables = {};
23
+ try {
24
+ variables = JSON.parse(variablesJson || '{}');
25
+ } catch (error) {
26
+ logger.error('Invalid JSON in variables argument');
27
+ logger.dim(` ${error.message}`);
28
+ process.exit(1);
29
+ }
30
+
31
+ // Add defaults
32
+ variables.DATE = variables.DATE || new Date().toISOString().split('T')[0];
33
+ variables.YEAR = variables.YEAR || new Date().getFullYear().toString();
34
+ variables.TIMESTAMP = variables.TIMESTAMP || new Date().toISOString();
35
+
36
+ // Render via hop-composer
37
+ const frameworkRoot = join(process.cwd(), 'framework');
38
+ const rendered = renderHOP(hopId, variables, { frameworkRoot });
39
+
40
+ if (options?.dryRun || !outputPath) {
41
+ logger.info(chalk.cyan('📋 HOP Preview:'));
42
+ logger.blank();
43
+ console.log(rendered);
44
+ logger.blank();
45
+ if (outputPath) logger.dim(`Would be written to: ${outputPath}`);
46
+ } else {
47
+ mkdirSync(dirname(outputPath), { recursive: true });
48
+ writeFileSync(outputPath, rendered, 'utf-8');
49
+ logger.success(`✅ HOP rendered: ${chalk.cyan(outputPath)}`);
50
+ }
51
+ } catch (error) {
52
+ logger.error(`Failed to render HOP: ${error.message}`);
53
+ process.exit(1);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * List available HOPs
59
+ */
60
+ export async function hopListCommand(options) {
61
+ logger.header('Available HOPs (Higher-Order Prompts)');
62
+ logger.blank();
63
+
64
+ const frameworkRoot = join(process.cwd(), 'framework');
65
+ const hops = listAvailableHOPs(frameworkRoot);
66
+
67
+ if (hops.length === 0) {
68
+ logger.warn('No HOPs found in framework/templates/meta-prompts/');
69
+ return;
70
+ }
71
+
72
+ const byType = {};
73
+ for (const hop of hops) {
74
+ const type = hop.type || 'other';
75
+ if (!byType[type]) byType[type] = [];
76
+ byType[type].push(hop);
77
+ }
78
+
79
+ for (const [type, list] of Object.entries(byType)) {
80
+ console.log(chalk.cyan(`\n ${type.toUpperCase()}`));
81
+ for (const hop of list) {
82
+ console.log(` ${chalk.white(hop.id.padEnd(30))} ${chalk.gray(hop.description || hop.path)}`);
83
+ }
84
+ }
85
+
86
+ logger.blank();
87
+ logger.dim(`Total: ${hops.length} HOPs`);
88
+ logger.dim(`Render: morph-spec hop render <hop-id> <output-file> '<variables-json>'`);
89
+ }
11
90
 
12
91
  /**
13
92
  * Render template command
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Thread Template CLI command — Thread type management
3
+ *
4
+ * Usage:
5
+ * morph-spec thread-template list
6
+ * morph-spec thread-template use <type> --feature=<feature>
7
+ */
8
+
9
+ import chalk from 'chalk';
10
+ import { THREAD_TYPES } from '../../lib/threads/thread-manager.js';
11
+
12
+ const THREAD_TYPE_INFO = {
13
+ [THREAD_TYPES.BASE]: {
14
+ name: 'B-Thread (Base)',
15
+ description: 'Standard single-agent thread. Sequential execution, all approval gates required.',
16
+ useCase: 'Default for simple and medium features',
17
+ phases: 'All standard phases',
18
+ approvalGates: 'Manual (all)',
19
+ maxConcurrent: 1
20
+ },
21
+ [THREAD_TYPES.PARALLEL]: {
22
+ name: 'P-Thread (Parallel)',
23
+ description: 'Multiple agents run simultaneously on different feature domains.',
24
+ useCase: 'Full-stack features with independent backend/frontend/infra work',
25
+ phases: 'All phases (parallel IMPLEMENT)',
26
+ approvalGates: 'Manual (all)',
27
+ maxConcurrent: 5
28
+ },
29
+ [THREAD_TYPES.FUSION]: {
30
+ name: 'F-Thread (Fusion)',
31
+ description: 'N agents independently generate solutions; best-of-N result is selected.',
32
+ useCase: 'High-uncertainty decisions, critical architecture choices, prototype evaluation',
33
+ phases: 'DESIGN → parallel IMPLEMENT → AGGREGATE → SYNC',
34
+ approvalGates: 'Manual select (or auto best-of-n)',
35
+ maxConcurrent: 3
36
+ },
37
+ [THREAD_TYPES.LONG_RUNNING]: {
38
+ name: 'L-Thread (Long-Running)',
39
+ description: 'Autonomous agent with stop hooks every 30 minutes for validation.',
40
+ useCase: 'Large scope features (>10 files), autonomous implementation without interruption',
41
+ phases: 'IMPLEMENT (continuous) with periodic validation',
42
+ approvalGates: 'Auto (stop hooks validate)',
43
+ maxConcurrent: 1
44
+ },
45
+ [THREAD_TYPES.ZERO_TOUCH]: {
46
+ name: 'Z-Thread (Zero-Touch)',
47
+ description: 'Fully autonomous execution. Auto-approves all gates, auto-commits on success.',
48
+ useCase: 'Maximum-trust features with >95% checkpoint pass rate',
49
+ phases: 'All phases (auto-approved)',
50
+ approvalGates: 'Auto (trust-based)',
51
+ maxConcurrent: 1
52
+ }
53
+ };
54
+
55
+ export async function threadTemplateListCommand(options) {
56
+ console.log(chalk.cyan('\n Thread Types (v3.0)\n'));
57
+ console.log(' ' + '─'.repeat(70));
58
+
59
+ for (const [type, info] of Object.entries(THREAD_TYPE_INFO)) {
60
+ console.log(`\n ${chalk.bold(info.name)}`);
61
+ console.log(` ${info.description}`);
62
+ console.log(` ${chalk.gray('Use case:')} ${info.useCase}`);
63
+ console.log(` ${chalk.gray('Phases:')} ${info.phases}`);
64
+ console.log(` ${chalk.gray('Gates:')} ${info.approvalGates}`);
65
+ console.log(` ${chalk.gray('Max concurrent:')} ${info.maxConcurrent}`);
66
+ }
67
+
68
+ console.log('\n ' + '─'.repeat(70));
69
+ console.log(chalk.gray('\n Set thread type: morph-spec thread-template use <type> --feature=<feature>\n'));
70
+ }
71
+
72
+ export async function threadTemplateUseCommand(type, options) {
73
+ if (!options.feature) {
74
+ console.error(chalk.red('--feature is required'));
75
+ process.exit(1);
76
+ }
77
+
78
+ if (!THREAD_TYPE_INFO[type]) {
79
+ console.error(chalk.red(`Unknown thread type: ${type}`));
80
+ console.error(chalk.gray(`Valid types: ${Object.keys(THREAD_TYPE_INFO).join(', ')}`));
81
+ process.exit(1);
82
+ }
83
+
84
+ const info = THREAD_TYPE_INFO[type];
85
+
86
+ // Special checks
87
+ if (type === THREAD_TYPES.ZERO_TOUCH) {
88
+ console.log(chalk.yellow('\n ⚠ Z-Thread requires maximum trust level (>95% checkpoint pass rate)'));
89
+ console.log(chalk.gray(' Check trust: morph-spec trust status\n'));
90
+ }
91
+
92
+ // Update feature state with thread type
93
+ try {
94
+ const { updateFeature } = await import('../../core/state/state-manager.js');
95
+ await updateFeature(options.feature, 'threadType', type);
96
+ console.log(chalk.green(`\n ✓ Thread type set: ${type} for feature: ${options.feature}`));
97
+ console.log(` ${info.name}: ${info.description}`);
98
+ console.log('');
99
+ } catch (err) {
100
+ console.error(chalk.red(` Error updating state: ${err.message}`));
101
+ process.exit(1);
102
+ }
103
+ }
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Threads CLI command — Thread lifecycle management
3
+ *
4
+ * Usage:
5
+ * morph-spec threads list [--feature=<f>] [--status=<s>]
6
+ * morph-spec threads status <id>
7
+ * morph-spec threads kill <id>
8
+ * morph-spec threads analytics [--feature=<f>]
9
+ * morph-spec threads wait-all <feature>
10
+ * morph-spec threads wait-any <feature>
11
+ */
12
+
13
+ import chalk from 'chalk';
14
+ import {
15
+ listThreads, getThread, killThread, getThreadAnalytics,
16
+ THREAD_STATUS, THREAD_TYPES
17
+ } from '../../lib/threads/thread-manager.js';
18
+ import { generateAsciiChart, generateTimelineChart } from '../../lib/analytics/analytics-engine.js';
19
+
20
+ const STATUS_COLORS = {
21
+ [THREAD_STATUS.PENDING]: chalk.yellow,
22
+ [THREAD_STATUS.RUNNING]: chalk.cyan,
23
+ [THREAD_STATUS.COMPLETED]: chalk.green,
24
+ [THREAD_STATUS.FAILED]: chalk.red,
25
+ [THREAD_STATUS.KILLED]: chalk.gray
26
+ };
27
+
28
+ const TYPE_ICONS = {
29
+ [THREAD_TYPES.BASE]: '◆',
30
+ [THREAD_TYPES.PARALLEL]: '⫸',
31
+ [THREAD_TYPES.FUSION]: '⊕',
32
+ [THREAD_TYPES.LONG_RUNNING]: '∞',
33
+ [THREAD_TYPES.ZERO_TOUCH]: '⚡'
34
+ };
35
+
36
+ function formatDuration(seconds) {
37
+ if (!seconds) return '—';
38
+ if (seconds < 60) return `${seconds}s`;
39
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
40
+ return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`;
41
+ }
42
+
43
+ /**
44
+ * List threads
45
+ */
46
+ export async function threadsListCommand(options) {
47
+ try {
48
+ const threads = listThreads({
49
+ feature: options.feature,
50
+ status: options.status,
51
+ type: options.type
52
+ });
53
+
54
+ if (threads.length === 0) {
55
+ console.log(chalk.gray('No threads found.'));
56
+ return;
57
+ }
58
+
59
+ console.log(chalk.cyan(`\n Threads (${threads.length})\n`));
60
+ console.log(
61
+ ' ' + 'ID'.padEnd(10) + ' ' +
62
+ 'Type'.padEnd(14) + ' ' +
63
+ 'Status'.padEnd(12) + ' ' +
64
+ 'Feature'.padEnd(20) + ' ' +
65
+ 'Agent'.padEnd(20) + ' ' +
66
+ 'Duration'
67
+ );
68
+ console.log(' ' + '─'.repeat(90));
69
+
70
+ for (const t of threads) {
71
+ const icon = TYPE_ICONS[t.type] || '◆';
72
+ const colorFn = STATUS_COLORS[t.status] || chalk.white;
73
+ const shortId = t.id.substring(0, 8);
74
+
75
+ console.log(
76
+ ' ' +
77
+ chalk.gray(shortId) + ' ' +
78
+ `${icon} ${t.type}`.padEnd(14) + ' ' +
79
+ colorFn(t.status.padEnd(12)) + ' ' +
80
+ (t.feature || '—').padEnd(20) + ' ' +
81
+ (t.agent || '—').padEnd(20) + ' ' +
82
+ formatDuration(t.duration)
83
+ );
84
+ }
85
+ console.log('');
86
+ } catch (err) {
87
+ console.error(chalk.red(`Error: ${err.message}`));
88
+ process.exit(1);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Show thread status detail
94
+ */
95
+ export async function threadsStatusCommand(id) {
96
+ try {
97
+ const thread = getThread(id);
98
+ if (!thread) {
99
+ console.error(chalk.red(`Thread not found: ${id}`));
100
+ process.exit(1);
101
+ }
102
+
103
+ const colorFn = STATUS_COLORS[thread.status] || chalk.white;
104
+ const icon = TYPE_ICONS[thread.type] || '◆';
105
+
106
+ console.log(chalk.cyan('\n Thread Detail\n'));
107
+ console.log(` ID: ${chalk.gray(thread.id)}`);
108
+ console.log(` Type: ${icon} ${thread.type}`);
109
+ console.log(` Status: ${colorFn(thread.status)}`);
110
+ console.log(` Feature: ${thread.feature || '—'}`);
111
+ console.log(` Agent: ${thread.agent || '—'}`);
112
+ console.log(` Mission: ${thread.mission || '—'}`);
113
+ console.log(` Created: ${thread.createdAt}`);
114
+ console.log(` Started: ${thread.startedAt || '—'}`);
115
+ console.log(` Ended: ${thread.completedAt || '—'}`);
116
+ console.log(` Duration: ${formatDuration(thread.duration)}`);
117
+
118
+ if (thread.metrics) {
119
+ console.log('\n Metrics:');
120
+ console.log(` Tool calls: ${thread.metrics.toolCalls || 0}`);
121
+ console.log(` Tokens used: ${(thread.metrics.tokensUsed || 0).toLocaleString()}`);
122
+ console.log(` Checkpoints OK: ${thread.metrics.checkpointsPassed || 0}`);
123
+ console.log(` Checkpoints KO: ${thread.metrics.checkpointsFailed || 0}`);
124
+ }
125
+
126
+ if (thread.events?.length > 0) {
127
+ console.log(`\n Recent events (${thread.events.length}):`);
128
+ thread.events.slice(-5).forEach(e => {
129
+ console.log(` ${chalk.gray(e.timestamp)} ${e.type}`);
130
+ });
131
+ }
132
+
133
+ if (thread.failureReason) {
134
+ console.log(`\n ${chalk.red('Failure:')} ${thread.failureReason}`);
135
+ }
136
+ console.log('');
137
+ } catch (err) {
138
+ console.error(chalk.red(`Error: ${err.message}`));
139
+ process.exit(1);
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Kill a thread
145
+ */
146
+ export async function threadsKillCommand(id) {
147
+ try {
148
+ const thread = killThread(id);
149
+ console.log(chalk.yellow(`✓ Thread ${id.substring(0, 8)} killed.`));
150
+ console.log(` Status: ${thread.status} | Duration: ${formatDuration(thread.duration)}`);
151
+ } catch (err) {
152
+ console.error(chalk.red(`Error: ${err.message}`));
153
+ process.exit(1);
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Show threads analytics dashboard
159
+ */
160
+ export async function threadsAnalyticsCommand(options) {
161
+ try {
162
+ const feature = options.feature;
163
+ if (!feature) {
164
+ console.error(chalk.red('--feature is required for analytics'));
165
+ process.exit(1);
166
+ }
167
+
168
+ const analytics = getThreadAnalytics(feature);
169
+
170
+ console.log(chalk.cyan(`\n Thread Analytics — ${feature}\n`));
171
+ console.log(` Total threads: ${analytics.total}`);
172
+ console.log(` By status:`);
173
+ for (const [status, count] of Object.entries(analytics.byStatus)) {
174
+ const colorFn = STATUS_COLORS[status] || chalk.white;
175
+ console.log(` ${colorFn(status.padEnd(12))} ${count}`);
176
+ }
177
+
178
+ console.log('\n By type:');
179
+ for (const [type, count] of Object.entries(analytics.byType)) {
180
+ const icon = TYPE_ICONS[type] || '◆';
181
+ console.log(` ${icon} ${type.padEnd(14)} ${count}`);
182
+ }
183
+
184
+ console.log(`\n Avg duration: ${formatDuration(analytics.avgDuration)}`);
185
+ console.log(` Total tool calls: ${analytics.totalToolCalls}`);
186
+ console.log(` Checkpoint pass rate: ${Math.round(analytics.checkpointPassRate * 100)}%`);
187
+
188
+ if (analytics.total > 0) {
189
+ const statusChart = generateAsciiChart(analytics.byStatus, { title: 'Threads by Status' });
190
+ console.log('\n' + statusChart);
191
+ }
192
+ console.log('');
193
+ } catch (err) {
194
+ console.error(chalk.red(`Error: ${err.message}`));
195
+ process.exit(1);
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Wait for all threads in a feature to complete
201
+ */
202
+ export async function threadsWaitAllCommand(feature, options) {
203
+ const timeoutMs = (options.timeout || 60) * 60 * 1000;
204
+ const pollInterval = 5000;
205
+ const start = Date.now();
206
+
207
+ console.log(chalk.cyan(`\n Waiting for all threads in: ${feature}\n`));
208
+
209
+ while (Date.now() - start < timeoutMs) {
210
+ const threads = listThreads({ feature });
211
+ const active = threads.filter(t =>
212
+ t.status === THREAD_STATUS.PENDING || t.status === THREAD_STATUS.RUNNING
213
+ );
214
+
215
+ if (active.length === 0) {
216
+ const failed = threads.filter(t => t.status === THREAD_STATUS.FAILED);
217
+ if (failed.length > 0) {
218
+ console.log(chalk.yellow(` ⚠ ${failed.length} thread(s) failed`));
219
+ process.exit(1);
220
+ }
221
+ console.log(chalk.green(` ✓ All ${threads.length} threads completed`));
222
+ return;
223
+ }
224
+
225
+ process.stdout.write(`\r Still running: ${active.length} thread(s)...`);
226
+ await new Promise(r => setTimeout(r, pollInterval));
227
+ }
228
+
229
+ console.error(chalk.red('\n Timeout waiting for threads'));
230
+ process.exit(1);
231
+ }
232
+
233
+ /**
234
+ * Wait for any thread to complete
235
+ */
236
+ export async function threadsWaitAnyCommand(feature, options) {
237
+ const timeoutMs = (options.timeout || 60) * 60 * 1000;
238
+ const pollInterval = 3000;
239
+ const start = Date.now();
240
+
241
+ console.log(chalk.cyan(`\n Waiting for first thread to complete in: ${feature}\n`));
242
+
243
+ while (Date.now() - start < timeoutMs) {
244
+ const threads = listThreads({ feature });
245
+ const done = threads.find(t =>
246
+ t.status === THREAD_STATUS.COMPLETED || t.status === THREAD_STATUS.FAILED
247
+ );
248
+
249
+ if (done) {
250
+ const colorFn = STATUS_COLORS[done.status] || chalk.white;
251
+ console.log(` ${colorFn('✓')} Thread ${done.id.substring(0, 8)} ${done.status}`);
252
+ if (done.agent) console.log(` Agent: ${done.agent}`);
253
+ return;
254
+ }
255
+
256
+ await new Promise(r => setTimeout(r, pollInterval));
257
+ }
258
+
259
+ console.error(chalk.red('\n Timeout waiting for thread'));
260
+ process.exit(1);
261
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Trust CLI — Trust level management for zero-touch execution
3
+ *
4
+ * Usage:
5
+ * morph-spec trust status [feature]
6
+ * morph-spec trust set <feature> <level> [reason]
7
+ * morph-spec trust history
8
+ * morph-spec trust auto-calculate <feature>
9
+ */
10
+
11
+ import chalk from 'chalk';
12
+ import {
13
+ getTrust,
14
+ setTrust,
15
+ clearTrustOverride,
16
+ getTrustHistory,
17
+ autoCalculateTrust,
18
+ TRUST_THRESHOLDS,
19
+ AUTO_APPROVE_GATES
20
+ } from '../../lib/trust/trust-manager.js';
21
+
22
+ /**
23
+ * Trust status — current trust level for a feature or all features
24
+ */
25
+ export async function trustStatusCommand(featureName, options) {
26
+ if (featureName) {
27
+ const trust = getTrust(featureName);
28
+
29
+ console.log(chalk.bold(`\n Trust Status — ${featureName}`));
30
+ console.log(' ' + '─'.repeat(50));
31
+
32
+ const levelColor = trust.level === 'maximum' ? chalk.green
33
+ : trust.level === 'high' ? chalk.cyan
34
+ : trust.level === 'medium' ? chalk.yellow
35
+ : chalk.red;
36
+
37
+ console.log(` Level: ${levelColor(trust.level.toUpperCase())}`);
38
+ console.log(` Pass Rate: ${Math.round((trust.passRate || 0) * 100)}%`);
39
+ console.log(` Checkpoints: ${trust.passed || 0}/${trust.total || 0} passed`);
40
+ console.log(` Source: ${trust.source || 'calculated'}`);
41
+
42
+ if (trust.source === 'manual') {
43
+ console.log(chalk.yellow(` Override: ${trust.overrideReason || 'No reason provided'}`));
44
+ }
45
+
46
+ console.log(`\n Auto-approved gates:`);
47
+ if (trust.autoApprove.length === 0) {
48
+ console.log(chalk.gray(' (none — manual approval required for all gates)'));
49
+ } else {
50
+ trust.autoApprove.forEach(g => console.log(chalk.green(` ✓ ${g}`)));
51
+ }
52
+
53
+ console.log(`\n Trust thresholds:`);
54
+ for (const [level, threshold] of Object.entries(TRUST_THRESHOLDS)) {
55
+ const gates = AUTO_APPROVE_GATES[level] || [];
56
+ const marker = trust.level === level ? chalk.bold(' ← current') : '';
57
+ console.log(` ${level.padEnd(10)} ≥ ${Math.round(threshold * 100)}% auto-approves: ${gates.join(', ') || 'none'}${marker}`);
58
+ }
59
+
60
+ console.log();
61
+ } else {
62
+ // Show all features
63
+ const history = getTrustHistory();
64
+ if (history.length === 0) {
65
+ console.log(chalk.yellow('\n No features found.\n'));
66
+ return;
67
+ }
68
+
69
+ console.log(chalk.bold('\n Trust Overview'));
70
+ console.log(' ' + '─'.repeat(70));
71
+ console.log(` ${'Feature'.padEnd(25)} ${'Level'.padEnd(10)} ${'Pass%'.padEnd(8)} ${'CPs'.padEnd(8)} Phase`);
72
+ console.log(' ' + '─'.repeat(70));
73
+
74
+ for (const f of history) {
75
+ const levelColor = f.level === 'maximum' ? chalk.green
76
+ : f.level === 'high' ? chalk.cyan
77
+ : f.level === 'medium' ? chalk.yellow
78
+ : chalk.red;
79
+
80
+ console.log(
81
+ ` ${f.feature.padEnd(25)} ` +
82
+ `${levelColor(f.level.padEnd(10))} ` +
83
+ `${String(Math.round(f.passRate * 100) + '%').padEnd(8)} ` +
84
+ `${String(f.checkpointsTotal).padEnd(8)} ` +
85
+ `${f.phase || 'N/A'}`
86
+ );
87
+ }
88
+ console.log();
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Trust set — manually override trust level
94
+ */
95
+ export async function trustSetCommand(featureName, level, reason, options) {
96
+ if (!featureName || !level) {
97
+ console.error(chalk.red('Usage: morph-spec trust set <feature> <level> [reason]'));
98
+ console.error(chalk.gray('Levels: low, medium, high, maximum'));
99
+ process.exit(1);
100
+ }
101
+
102
+ const effectiveReason = reason || `Manual override to ${level}`;
103
+
104
+ try {
105
+ const result = setTrust(featureName, level, effectiveReason);
106
+
107
+ console.log(chalk.green(`\n✓ Trust updated for ${featureName}`));
108
+ console.log(` Level: ${result.level}`);
109
+ console.log(` Auto-approves: ${result.autoApprove.join(', ') || 'none'}`);
110
+ console.log(` Reason: ${result.reason}`);
111
+ console.log(chalk.gray('\n Note: Use "trust auto-calculate" to revert to calculated trust.\n'));
112
+ } catch (err) {
113
+ console.error(chalk.red(`Error: ${err.message}`));
114
+ process.exit(1);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Trust history — table of all features with checkpoint pass rates
120
+ */
121
+ export async function trustHistoryCommand(options) {
122
+ const history = getTrustHistory();
123
+
124
+ console.log(chalk.bold('\n Trust History'));
125
+ console.log(' ' + '─'.repeat(80));
126
+
127
+ if (history.length === 0) {
128
+ console.log(chalk.gray(' No features found.\n'));
129
+ return;
130
+ }
131
+
132
+ for (const f of history) {
133
+ const levelColor = f.level === 'maximum' ? chalk.green
134
+ : f.level === 'high' ? chalk.cyan
135
+ : f.level === 'medium' ? chalk.yellow
136
+ : chalk.red;
137
+
138
+ console.log(`\n ${chalk.bold(f.feature)}`);
139
+ console.log(` Trust: ${levelColor(f.level)} (${Math.round(f.passRate * 100)}% pass rate)`);
140
+ console.log(` Checkpoints: ${f.checkpointsPassed}/${f.checkpointsTotal} passed`);
141
+ console.log(` Phase: ${f.phase || 'N/A'} | Status: ${f.status || 'N/A'}`);
142
+ console.log(` Source: ${f.source}`);
143
+
144
+ if (f.autoApprove.length > 0) {
145
+ console.log(` Auto-approves: ${chalk.green(f.autoApprove.join(', '))}`);
146
+ }
147
+ }
148
+
149
+ console.log('\n ' + '─'.repeat(80));
150
+ console.log(chalk.gray(` Total features: ${history.length}\n`));
151
+ }
152
+
153
+ /**
154
+ * Trust auto-calculate — recalculate from checkpoint history
155
+ */
156
+ export async function trustAutoCalculateCommand(featureName, options) {
157
+ if (!featureName) {
158
+ console.error(chalk.red('Usage: morph-spec trust auto-calculate <feature>'));
159
+ process.exit(1);
160
+ }
161
+
162
+ try {
163
+ const result = autoCalculateTrust(featureName);
164
+
165
+ const levelColor = result.level === 'maximum' ? chalk.green
166
+ : result.level === 'high' ? chalk.cyan
167
+ : result.level === 'medium' ? chalk.yellow
168
+ : chalk.red;
169
+
170
+ console.log(chalk.bold(`\n Trust Calculated — ${featureName}`));
171
+ console.log(' ' + '─'.repeat(40));
172
+ console.log(` Level: ${levelColor(result.level.toUpperCase())}`);
173
+ console.log(` Pass Rate: ${Math.round(result.passRate * 100)}%`);
174
+ console.log(` Checkpoints: ${result.passed}/${result.total} passed`);
175
+ console.log(` Auto-approves: ${result.autoApprove.join(', ') || 'none'}`);
176
+
177
+ if (result.level === 'maximum') {
178
+ console.log(chalk.green('\n ✓ Feature is eligible for zero-touch execution!'));
179
+ console.log(chalk.gray(' All gates will be auto-approved.\n'));
180
+ } else {
181
+ const nextLevel = result.passRate < TRUST_THRESHOLDS.medium ? 'medium'
182
+ : result.passRate < TRUST_THRESHOLDS.high ? 'high'
183
+ : 'maximum';
184
+ const needed = Math.ceil(TRUST_THRESHOLDS[nextLevel] * result.total) - result.passed;
185
+ console.log(chalk.gray(`\n Next level: ${nextLevel} (need ${needed} more passing checkpoints)\n`));
186
+ }
187
+ } catch (err) {
188
+ console.error(chalk.red(`Error: ${err.message}`));
189
+ process.exit(1);
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Trust clear — remove manual override
195
+ */
196
+ export async function trustClearCommand(featureName, options) {
197
+ if (!featureName) {
198
+ console.error(chalk.red('Usage: morph-spec trust clear <feature>'));
199
+ process.exit(1);
200
+ }
201
+
202
+ clearTrustOverride(featureName);
203
+ console.log(chalk.green(`\n✓ Manual trust override cleared for ${featureName}`));
204
+ console.log(chalk.gray(' Trust will now be calculated from checkpoint history.\n'));
205
+ }
@@ -4,18 +4,18 @@
4
4
  */
5
5
 
6
6
  import chalk from 'chalk';
7
- import { ProjectScanner } from './scanner/project-scanner.js';
8
- import { ContextSanitizer } from './sanitizer/context-sanitizer.js';
9
- import { LLMAnalyzer } from './llm/analyzer.js';
10
- import { ConfigGenerator } from './generator/config-generator.js';
11
- import { UserReview } from './ui/user-review.js';
12
- import { InteractiveWizard } from './ui/interactive-wizard.js';
13
- import { FileWriter } from './writer/file-writer.js';
7
+ import { ProjectScanner } from '../scanner/project-scanner.js';
8
+ import { ContextSanitizer } from '../sanitizer/context-sanitizer.js';
9
+ import { LLMAnalyzer } from '../llm/analyzer.js';
10
+ import { ConfigGenerator } from '../generator/config-generator.js';
11
+ import { UserReview } from '../ui/user-review.js';
12
+ import { InteractiveWizard } from '../ui/interactive-wizard.js';
13
+ import { FileWriter } from '../writer/file-writer.js';
14
14
  import { readFile, access } from 'fs/promises';
15
15
  import { join } from 'path';
16
16
 
17
17
  /**
18
- * @typedef {import('./types/index.js').GeneratedConfigs} GeneratedConfigs
18
+ * @typedef {import('../types/index.js').GeneratedConfigs} GeneratedConfigs
19
19
  */
20
20
 
21
21
  /**