dhurandhar 1.0.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 (54) hide show
  1. package/.dhurandhar-session-start.md +242 -0
  2. package/LICENSE +21 -0
  3. package/README.md +416 -0
  4. package/docs/ARCHITECTURE_V2.md +249 -0
  5. package/docs/DECISION_REGISTRY.md +357 -0
  6. package/docs/IMPLEMENTATION_PERSONAS.md +406 -0
  7. package/docs/PLUGGABLE_STRATEGIES.md +439 -0
  8. package/docs/SYSTEM_OBSERVER.md +433 -0
  9. package/docs/TEST_FIRST_AGILE.md +359 -0
  10. package/docs/architecture.md +279 -0
  11. package/docs/engineering-first-philosophy.md +263 -0
  12. package/docs/getting-started.md +218 -0
  13. package/docs/module-development.md +323 -0
  14. package/docs/strategy-example.md +299 -0
  15. package/docs/test-first-example.md +392 -0
  16. package/package.json +79 -0
  17. package/src/core/README.md +92 -0
  18. package/src/core/agent-instructions/backend-developer.md +412 -0
  19. package/src/core/agent-instructions/devops-engineer.md +372 -0
  20. package/src/core/agent-instructions/dhurandhar-council.md +547 -0
  21. package/src/core/agent-instructions/edge-case-hunter.md +322 -0
  22. package/src/core/agent-instructions/frontend-developer.md +494 -0
  23. package/src/core/agent-instructions/lead-system-architect.md +631 -0
  24. package/src/core/agent-instructions/system-observer.md +319 -0
  25. package/src/core/agent-instructions/test-architect.md +284 -0
  26. package/src/core/module.yaml +54 -0
  27. package/src/core/schemas/design-module-schema.yaml +995 -0
  28. package/src/core/schemas/system-design-map-schema.yaml +324 -0
  29. package/src/modules/example/README.md +130 -0
  30. package/src/modules/example/module.yaml +252 -0
  31. package/tools/cli/commands/audit.js +267 -0
  32. package/tools/cli/commands/config.js +113 -0
  33. package/tools/cli/commands/context.js +170 -0
  34. package/tools/cli/commands/decisions.js +398 -0
  35. package/tools/cli/commands/entity.js +218 -0
  36. package/tools/cli/commands/epic.js +125 -0
  37. package/tools/cli/commands/install.js +172 -0
  38. package/tools/cli/commands/module.js +109 -0
  39. package/tools/cli/commands/service.js +167 -0
  40. package/tools/cli/commands/story.js +225 -0
  41. package/tools/cli/commands/strategy.js +294 -0
  42. package/tools/cli/commands/test.js +277 -0
  43. package/tools/cli/commands/validate.js +107 -0
  44. package/tools/cli/dhurandhar.js +212 -0
  45. package/tools/lib/config-manager.js +170 -0
  46. package/tools/lib/filesystem.js +126 -0
  47. package/tools/lib/module-installer.js +61 -0
  48. package/tools/lib/module-manager.js +149 -0
  49. package/tools/lib/sdm-manager.js +982 -0
  50. package/tools/lib/test-engine.js +255 -0
  51. package/tools/lib/test-templates/api-client.template.js +100 -0
  52. package/tools/lib/test-templates/vitest.config.template.js +37 -0
  53. package/tools/lib/validators/config-validator.js +113 -0
  54. package/tools/lib/validators/module-validator.js +137 -0
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Epic Command - Agile Blueprint Management
3
+ * Manage Epics (high-level system capabilities)
4
+ */
5
+
6
+ import * as clack from '@clack/prompts';
7
+ import chalk from 'chalk';
8
+ import { SDMManager } from '../../lib/sdm-manager.js';
9
+ import { ConfigManager } from '../../lib/config-manager.js';
10
+
11
+ export async function epicCommand(options) {
12
+ try {
13
+ const sdmManager = new SDMManager(process.cwd());
14
+ const configManager = new ConfigManager(process.cwd());
15
+
16
+ if (!configManager.exists()) {
17
+ clack.log.error(chalk.red('Framework not installed.'));
18
+ clack.log.info('Run: dhurandhar install');
19
+ process.exit(1);
20
+ }
21
+
22
+ if (options.list) {
23
+ await listEpics(sdmManager);
24
+ } else if (options.add) {
25
+ await addEpic(sdmManager, options.add);
26
+ } else {
27
+ console.log(chalk.cyan('Usage:'));
28
+ console.log(' dhurandhar epic --list List all epics');
29
+ console.log(' dhurandhar epic --add "Epic Name" Add epic');
30
+ }
31
+
32
+ } catch (error) {
33
+ clack.log.error(chalk.red('Epic operation failed:'), error.message);
34
+ process.exit(1);
35
+ }
36
+ }
37
+
38
+ async function listEpics(sdmManager) {
39
+ const sdm = await sdmManager.load();
40
+
41
+ if (!sdm.agile_blueprint || !sdm.agile_blueprint.epics || sdm.agile_blueprint.epics.length === 0) {
42
+ console.log(chalk.dim(' No epics defined yet.'));
43
+ console.log('');
44
+ console.log(chalk.cyan('Add one:'));
45
+ console.log(' dhurandhar epic add "User Authentication & Authorization"');
46
+ return;
47
+ }
48
+
49
+ clack.intro(chalk.cyan.bold(`Epics (${sdm.agile_blueprint.epics.length})`));
50
+
51
+ console.log('');
52
+ sdm.agile_blueprint.epics.forEach(epic => {
53
+ const storyCount = epic.stories?.length || 0;
54
+ console.log(chalk.bold(`${epic.id}: ${epic.name}`));
55
+ console.log(` Stories: ${storyCount}`);
56
+ if (epic.description) {
57
+ console.log(` ${chalk.dim(epic.description)}`);
58
+ }
59
+ console.log('');
60
+ });
61
+
62
+ clack.outro('');
63
+ }
64
+
65
+ async function addEpic(sdmManager, epicName) {
66
+ clack.intro(chalk.cyan.bold('Add Epic'));
67
+
68
+ const name = typeof epicName === 'string' ? epicName : null;
69
+
70
+ let epicTitle = name;
71
+
72
+ if (!epicTitle) {
73
+ epicTitle = await clack.text({
74
+ message: 'Epic name (system capability):',
75
+ placeholder: 'User Authentication & Authorization',
76
+ validate: (v) => !v ? 'Required' : undefined,
77
+ });
78
+
79
+ if (clack.isCancel(epicTitle)) {
80
+ clack.cancel('Cancelled.');
81
+ process.exit(0);
82
+ }
83
+ }
84
+
85
+ // Technical description
86
+ const description = await clack.text({
87
+ message: 'Technical description (optional):',
88
+ placeholder: 'JWT-based auth with OAuth2 social login',
89
+ });
90
+
91
+ if (clack.isCancel(description)) {
92
+ clack.cancel('Cancelled.');
93
+ process.exit(0);
94
+ }
95
+
96
+ // Generate Epic ID
97
+ const sdm = await sdmManager.load();
98
+ if (!sdm.agile_blueprint) {
99
+ sdm.agile_blueprint = { epics: [], test_suite_status: {} };
100
+ }
101
+ if (!sdm.agile_blueprint.epics) {
102
+ sdm.agile_blueprint.epics = [];
103
+ }
104
+
105
+ const epicId = `EPIC-${String(sdm.agile_blueprint.epics.length + 1).padStart(3, '0')}`;
106
+
107
+ // Create Epic
108
+ const epic = {
109
+ id: epicId,
110
+ name: epicTitle,
111
+ description: description || undefined,
112
+ acceptance_criteria: [],
113
+ stories: [],
114
+ };
115
+
116
+ sdm.agile_blueprint.epics.push(epic);
117
+ await sdmManager.save(sdm);
118
+
119
+ clack.outro(chalk.green(`✓ Epic ${epicId} added`));
120
+
121
+ console.log('');
122
+ console.log(chalk.cyan('Next: Add Stories'));
123
+ console.log(` dhurandhar story add --epic ${epicId}`);
124
+ console.log('');
125
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Install Command - Engineering-First Installation
3
+ * Direct action model: 3 technical questions max, no justification loops
4
+ */
5
+
6
+ import * as clack from '@clack/prompts';
7
+ import chalk from 'chalk';
8
+ import { existsSync } from 'fs';
9
+ import { join } from 'path';
10
+ import { ConfigManager } from '../../lib/config-manager.js';
11
+ import { ModuleInstaller } from '../../lib/module-installer.js';
12
+ import { FileSystem } from '../../lib/filesystem.js';
13
+ import { SDMManager } from '../../lib/sdm-manager.js';
14
+
15
+ export async function installCommand(options) {
16
+ console.clear();
17
+
18
+ clack.intro(chalk.cyan.bold('🔧 Dhurandhar - Engineering-First System Design'));
19
+
20
+ try {
21
+ const targetDir = options.directory || process.cwd();
22
+
23
+ // Check if already installed
24
+ const configPath = join(targetDir, '.dhurandhar', 'config.yaml');
25
+ if (existsSync(configPath) && !options.yes) {
26
+ const shouldReinstall = await clack.confirm({
27
+ message: 'Framework already installed. Reinstall?',
28
+ initialValue: false,
29
+ });
30
+
31
+ if (clack.isCancel(shouldReinstall) || !shouldReinstall) {
32
+ clack.cancel('Cancelled.');
33
+ process.exit(0);
34
+ }
35
+ }
36
+
37
+ // ENGINEERING-FIRST: Only 3 technical questions
38
+ let config = {};
39
+ let techConfig = {};
40
+
41
+ if (!options.yes) {
42
+ // Question 1: Project identifier
43
+ const projectName = await clack.text({
44
+ message: 'Project identifier (kebab-case):',
45
+ placeholder: 'my-system',
46
+ validate: (value) => {
47
+ if (!value) return 'Required';
48
+ if (!/^[a-z0-9-]+$/.test(value)) {
49
+ return 'Must be lowercase, alphanumeric, hyphens only';
50
+ }
51
+ },
52
+ });
53
+
54
+ if (clack.isCancel(projectName)) {
55
+ clack.cancel('Cancelled.');
56
+ process.exit(0);
57
+ }
58
+
59
+ // Question 2: Architecture type (technical decision)
60
+ const architectureType = await clack.select({
61
+ message: 'Architecture type:',
62
+ options: [
63
+ { value: 'microservices', label: 'Microservices', hint: 'Multiple services, independent deployment' },
64
+ { value: 'monolith', label: 'Monolith', hint: 'Single deployable unit' },
65
+ { value: 'serverless', label: 'Serverless', hint: 'FaaS, event-driven' },
66
+ { value: 'hybrid', label: 'Hybrid', hint: 'Mix of patterns' },
67
+ ],
68
+ initialValue: 'microservices',
69
+ });
70
+
71
+ if (clack.isCancel(architectureType)) {
72
+ clack.cancel('Cancelled.');
73
+ process.exit(0);
74
+ }
75
+
76
+ // Question 3: Primary tech stack
77
+ const primaryLanguage = await clack.select({
78
+ message: 'Primary language:',
79
+ options: [
80
+ { value: 'go', label: 'Go', hint: 'Performance, concurrency' },
81
+ { value: 'typescript', label: 'TypeScript', hint: 'Type-safe JavaScript' },
82
+ { value: 'python', label: 'Python', hint: 'Rapid development, ML/AI' },
83
+ { value: 'rust', label: 'Rust', hint: 'Systems programming, safety' },
84
+ { value: 'java', label: 'Java', hint: 'Enterprise, JVM ecosystem' },
85
+ ],
86
+ initialValue: 'go',
87
+ });
88
+
89
+ if (clack.isCancel(primaryLanguage)) {
90
+ clack.cancel('Cancelled.');
91
+ process.exit(0);
92
+ }
93
+
94
+ config = {
95
+ projectName,
96
+ userName: 'Engineer', // Default, not critical
97
+ outputFolder: '_dhurandhar-output',
98
+ };
99
+
100
+ techConfig = {
101
+ architectureType,
102
+ primaryLanguage,
103
+ };
104
+ } else {
105
+ config = {
106
+ projectName: 'dhurandhar-project',
107
+ userName: 'Engineer',
108
+ outputFolder: '_dhurandhar-output',
109
+ };
110
+ techConfig = {
111
+ architectureType: 'microservices',
112
+ primaryLanguage: 'go',
113
+ };
114
+ }
115
+
116
+ // Auto-install core only (no module selection prompts)
117
+ const selectedModules = options.modules || ['core'];
118
+
119
+ // Perform installation
120
+ const spinner = clack.spinner();
121
+
122
+ spinner.start('Installing framework...');
123
+
124
+ // Create directory structure
125
+ await FileSystem.ensureDirectories(targetDir);
126
+
127
+ // Initialize configuration
128
+ const configManager = new ConfigManager(targetDir);
129
+ await configManager.initialize(config);
130
+
131
+ spinner.message('Initializing System Design Map...');
132
+
133
+ // Initialize SDM (System Design Map) for persistent state
134
+ const sdmManager = new SDMManager(targetDir);
135
+ await sdmManager.initialize(config.projectName);
136
+
137
+ // Update SDM with architecture type
138
+ const sdm = await sdmManager.load();
139
+ sdm.metadata.architecture_type = techConfig.architectureType;
140
+ sdm.tech_stack.languages = [techConfig.primaryLanguage];
141
+ await sdmManager.save(sdm);
142
+
143
+ spinner.message('Installing core module...');
144
+
145
+ // Install modules
146
+ const installer = new ModuleInstaller(targetDir);
147
+ await installer.installModules(selectedModules);
148
+
149
+ spinner.stop('Framework installed!');
150
+
151
+ clack.outro(chalk.green('✓ Ready for engineering'));
152
+
153
+ // Show next steps - ENGINEERING-FOCUSED
154
+ console.log('');
155
+ console.log(chalk.cyan('System initialized:'));
156
+ console.log(` ${chalk.bold('SYSTEM_DESIGN_MAP.yaml')} - Persistent architecture state`);
157
+ console.log(` ${chalk.dim('.dhurandhar/config.yaml')} - Framework configuration`);
158
+ console.log('');
159
+ console.log(chalk.cyan('Add your first service:'));
160
+ console.log(` ${chalk.bold('dhurandhar service add "auth-service: JWT auth using ' + techConfig.primaryLanguage + '"')}`);
161
+ console.log('');
162
+ console.log(chalk.cyan('Or add an entity:'));
163
+ console.log(` ${chalk.bold('dhurandhar entity add User')}`);
164
+ console.log('');
165
+ console.log(chalk.dim('The SDM persists context across sessions - no rediscovery needed.'));
166
+ console.log('');
167
+
168
+ } catch (error) {
169
+ clack.log.error(chalk.red('Installation failed:'), error.message);
170
+ process.exit(1);
171
+ }
172
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Module Command
3
+ * Manages framework modules
4
+ */
5
+
6
+ import * as clack from '@clack/prompts';
7
+ import chalk from 'chalk';
8
+ import { ModuleManager } from '../../lib/module-manager.js';
9
+ import { ConfigManager } from '../../lib/config-manager.js';
10
+
11
+ export async function moduleCommand(options) {
12
+ try {
13
+ const moduleManager = new ModuleManager(process.cwd());
14
+ const configManager = new ConfigManager(process.cwd());
15
+
16
+ if (!configManager.exists()) {
17
+ clack.log.error(chalk.red('Dhurandhar is not installed in this directory.'));
18
+ clack.log.info('Run: dhurandhar install');
19
+ process.exit(1);
20
+ }
21
+
22
+ if (options.list) {
23
+ // List available modules
24
+ clack.intro(chalk.cyan.bold('Available Modules'));
25
+
26
+ const modules = await moduleManager.listAvailable();
27
+ const installed = await moduleManager.listInstalled();
28
+
29
+ console.log('');
30
+ modules.forEach(module => {
31
+ const isInstalled = installed.includes(module.code);
32
+ const status = isInstalled ? chalk.green('✓ installed') : chalk.dim('not installed');
33
+ console.log(` ${chalk.bold(module.code)} - ${module.name}`);
34
+ console.log(` ${status}`);
35
+ console.log(` ${chalk.dim(module.description)}`);
36
+ console.log('');
37
+ });
38
+
39
+ clack.outro(chalk.dim(`Total: ${modules.length} modules available`));
40
+
41
+ } else if (options.info) {
42
+ // Show module information
43
+ const moduleInfo = await moduleManager.getInfo(options.info);
44
+
45
+ if (!moduleInfo) {
46
+ clack.log.error(chalk.red(`Module "${options.info}" not found.`));
47
+ process.exit(1);
48
+ }
49
+
50
+ clack.intro(chalk.cyan.bold(`Module: ${moduleInfo.name}`));
51
+
52
+ console.log('');
53
+ console.log(chalk.bold('Details:'));
54
+ console.log(` Code: ${chalk.cyan(moduleInfo.code)}`);
55
+ console.log(` Name: ${chalk.cyan(moduleInfo.name)}`);
56
+ console.log(` Version: ${chalk.cyan(moduleInfo.version || '1.0.0')}`);
57
+ console.log(` Description: ${moduleInfo.description}`);
58
+ console.log('');
59
+
60
+ if (moduleInfo.dependencies && moduleInfo.dependencies.length > 0) {
61
+ console.log(chalk.bold('Dependencies:'));
62
+ moduleInfo.dependencies.forEach(dep => {
63
+ console.log(` - ${dep}`);
64
+ });
65
+ console.log('');
66
+ }
67
+
68
+ clack.outro('');
69
+
70
+ } else if (options.add) {
71
+ // Add a module
72
+ clack.intro(chalk.cyan.bold('Add Module'));
73
+
74
+ const spinner = clack.spinner();
75
+ spinner.start(`Installing module: ${options.add}`);
76
+
77
+ await moduleManager.install(options.add);
78
+
79
+ spinner.stop(`Module "${options.add}" installed successfully!`);
80
+ clack.outro(chalk.green('✓ Done'));
81
+
82
+ } else if (options.remove) {
83
+ // Remove a module
84
+ const confirm = await clack.confirm({
85
+ message: `Remove module "${options.remove}"?`,
86
+ });
87
+
88
+ if (clack.isCancel(confirm) || !confirm) {
89
+ clack.cancel('Operation cancelled.');
90
+ process.exit(0);
91
+ }
92
+
93
+ await moduleManager.uninstall(options.remove);
94
+ clack.outro(chalk.green(`✓ Module "${options.remove}" removed.`));
95
+
96
+ } else {
97
+ // No option provided, show help
98
+ console.log(chalk.cyan('Usage:'));
99
+ console.log(' dhurandhar module --list List all available modules');
100
+ console.log(' dhurandhar module --info <module> Show module information');
101
+ console.log(' dhurandhar module --add <module> Add a module');
102
+ console.log(' dhurandhar module --remove <module> Remove a module');
103
+ }
104
+
105
+ } catch (error) {
106
+ clack.log.error(chalk.red('Module operation failed:'), error.message);
107
+ process.exit(1);
108
+ }
109
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Service Command - Direct-Action Service Management
3
+ * Add/modify services with technical specs only, no justification loops
4
+ */
5
+
6
+ import * as clack from '@clack/prompts';
7
+ import chalk from 'chalk';
8
+ import { SDMManager } from '../../lib/sdm-manager.js';
9
+ import { ConfigManager } from '../../lib/config-manager.js';
10
+
11
+ export async function serviceCommand(options) {
12
+ try {
13
+ const sdmManager = new SDMManager(process.cwd());
14
+ const configManager = new ConfigManager(process.cwd());
15
+
16
+ if (!configManager.exists()) {
17
+ clack.log.error(chalk.red('Framework not installed.'));
18
+ clack.log.info('Run: dhurandhar install');
19
+ process.exit(1);
20
+ }
21
+
22
+ if (options.list) {
23
+ // List services
24
+ const sdm = await sdmManager.load();
25
+
26
+ clack.intro(chalk.cyan.bold(`Services (${sdm.services.length})`));
27
+
28
+ if (sdm.services.length === 0) {
29
+ console.log(chalk.dim(' No services defined yet.'));
30
+ console.log('');
31
+ console.log(chalk.cyan('Add one:'));
32
+ console.log(' dhurandhar service add "auth-service: JWT auth using Go/Echo"');
33
+ } else {
34
+ console.log('');
35
+ sdm.services.forEach(s => {
36
+ console.log(chalk.bold(`${s.name}`));
37
+ console.log(` ${chalk.dim(s.scope)}`);
38
+ console.log(` Stack: ${chalk.cyan(s.tech_stack.language)}/${chalk.cyan(s.tech_stack.framework)}`);
39
+ if (s.tech_stack.database) {
40
+ console.log(` Database: ${chalk.cyan(s.tech_stack.database)}`);
41
+ }
42
+ if (s.api) {
43
+ console.log(` API: ${s.api.type} ${s.api.base_path || ''} ${s.api.port ? ':' + s.api.port : ''}`);
44
+ }
45
+ console.log('');
46
+ });
47
+ }
48
+
49
+ clack.outro('');
50
+
51
+ } else if (options.add) {
52
+ // Add service - DIRECT ACTION, max 3 questions
53
+ clack.intro(chalk.cyan.bold('Add Service'));
54
+
55
+ // Parse quick spec if provided: "service-name: description"
56
+ let serviceName, serviceScope;
57
+
58
+ if (typeof options.add === 'string' && options.add.includes(':')) {
59
+ const parts = options.add.split(':');
60
+ serviceName = parts[0].trim();
61
+ serviceScope = parts.slice(1).join(':').trim();
62
+ } else {
63
+ serviceName = typeof options.add === 'string' ? options.add : null;
64
+ }
65
+
66
+ // Question 1: Service name (if not provided)
67
+ if (!serviceName) {
68
+ serviceName = await clack.text({
69
+ message: 'Service name (kebab-case):',
70
+ placeholder: 'auth-service',
71
+ validate: (v) => !v ? 'Required' : !/^[a-z0-9-]+$/.test(v) ? 'Use kebab-case' : undefined,
72
+ });
73
+
74
+ if (clack.isCancel(serviceName)) {
75
+ clack.cancel('Cancelled.');
76
+ process.exit(0);
77
+ }
78
+ }
79
+
80
+ // Question 2: Scope (if not provided)
81
+ if (!serviceScope) {
82
+ serviceScope = await clack.text({
83
+ message: 'What does it do? (1-2 sentences):',
84
+ placeholder: 'Handles JWT authentication and session management',
85
+ validate: (v) => !v ? 'Required' : undefined,
86
+ });
87
+
88
+ if (clack.isCancel(serviceScope)) {
89
+ clack.cancel('Cancelled.');
90
+ process.exit(0);
91
+ }
92
+ }
93
+
94
+ // Question 3: Tech stack
95
+ const sdm = await sdmManager.load();
96
+ const defaultLang = sdm.tech_stack.languages[0] || 'go';
97
+
98
+ const language = await clack.select({
99
+ message: 'Language:',
100
+ options: [
101
+ { value: 'go', label: 'Go' },
102
+ { value: 'typescript', label: 'TypeScript' },
103
+ { value: 'python', label: 'Python' },
104
+ { value: 'rust', label: 'Rust' },
105
+ { value: 'java', label: 'Java' },
106
+ ],
107
+ initialValue: defaultLang,
108
+ });
109
+
110
+ if (clack.isCancel(language)) {
111
+ clack.cancel('Cancelled.');
112
+ process.exit(0);
113
+ }
114
+
115
+ // Auto-select common framework for language
116
+ const frameworkMap = {
117
+ go: 'Echo',
118
+ typescript: 'Express',
119
+ python: 'FastAPI',
120
+ rust: 'Actix',
121
+ java: 'Spring',
122
+ };
123
+
124
+ const framework = frameworkMap[language];
125
+ const database = 'PostgreSQL'; // Default
126
+
127
+ // Build service object
128
+ const service = {
129
+ name: serviceName,
130
+ scope: serviceScope,
131
+ tech_stack: {
132
+ language: language.charAt(0).toUpperCase() + language.slice(1),
133
+ framework,
134
+ database,
135
+ },
136
+ api: {
137
+ type: 'rest',
138
+ base_path: `/api/v1/${serviceName.replace('-service', '')}`,
139
+ port: 8080 + sdm.services.length, // Auto-increment
140
+ },
141
+ dependencies: [],
142
+ data_access: [],
143
+ };
144
+
145
+ // Add to SDM
146
+ await sdmManager.addService(service);
147
+
148
+ clack.outro(chalk.green(`✓ Service "${serviceName}" added to architecture`));
149
+
150
+ console.log('');
151
+ console.log(chalk.cyan('Updated SYSTEM_DESIGN_MAP.yaml'));
152
+ console.log(chalk.dim('Context persisted for next session.'));
153
+ console.log('');
154
+
155
+ } else {
156
+ // Show help
157
+ console.log(chalk.cyan('Usage:'));
158
+ console.log(' dhurandhar service --list List all services');
159
+ console.log(' dhurandhar service --add "name: description" Add service with quick spec');
160
+ console.log(' dhurandhar service --add Add service interactively');
161
+ }
162
+
163
+ } catch (error) {
164
+ clack.log.error(chalk.red('Service operation failed:'), error.message);
165
+ process.exit(1);
166
+ }
167
+ }