mdboard 2.1.5 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdboard",
3
- "version": "2.1.5",
3
+ "version": "2.2.0",
4
4
  "description": "Git-based project management dashboard. Reads markdown files with YAML frontmatter and serves a visual kanban board, table, milestones, and metrics views.",
5
5
  "main": "./src/server/server.js",
6
6
  "bin": {
package/src/cli/init.js CHANGED
@@ -22,7 +22,7 @@ const today = new Date().toISOString().split('T')[0];
22
22
  const args = process.argv.slice(2).filter(a => a !== 'init');
23
23
 
24
24
  // Parse flags
25
- const preset = process.env.MDBOARD_PRESET || parseFlag('preset') || configEngine.DEFAULT_PRESET;
25
+ const presetFlag = process.env.MDBOARD_PRESET || parseFlag('preset');
26
26
  function parseFlag(flag) {
27
27
  for (let i = 0; i < args.length; i++) {
28
28
  if (args[i] === '--' + flag && args[i + 1]) return args[i + 1];
@@ -52,14 +52,15 @@ if (fs.existsSync(projectPath)) {
52
52
  process.exit(0);
53
53
  }
54
54
 
55
- // Validate preset exists
56
- const presetDir = path.join(configEngine.PRESETS_DIR, preset);
57
- if (!fs.existsSync(presetDir)) {
58
- const available = fs.readdirSync(configEngine.PRESETS_DIR).filter(d => {
59
- return fs.statSync(path.join(configEngine.PRESETS_DIR, d)).isDirectory();
60
- });
61
- console.error('\n Error: unknown preset "' + preset + '"');
62
- console.error(' Available presets: ' + available.join(', ') + '\n');
55
+ // List available presets
56
+ const availablePresets = fs.readdirSync(configEngine.PRESETS_DIR).filter(function (d) {
57
+ return fs.statSync(path.join(configEngine.PRESETS_DIR, d)).isDirectory();
58
+ });
59
+
60
+ // Validate preset flag if provided
61
+ if (presetFlag && !availablePresets.includes(presetFlag)) {
62
+ console.error('\n Error: unknown preset "' + presetFlag + '"');
63
+ console.error(' Available presets: ' + availablePresets.join(', ') + '\n');
63
64
  process.exit(1);
64
65
  }
65
66
 
@@ -67,13 +68,52 @@ if (!fs.existsSync(presetDir)) {
67
68
  const agentsFlag = parseFlag('agents');
68
69
 
69
70
  if (nameArg) {
70
- resolveAgentTargets(function (targets) { scaffold(nameArg, targets); });
71
+ resolvePreset(function (selectedPreset) {
72
+ resolveAgentTargets(function (targets) { scaffold(nameArg, selectedPreset, targets); });
73
+ });
71
74
  } else {
72
75
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
73
76
  rl.question(' Workspace name: ', function (answer) {
74
77
  rl.close();
75
78
  const name = answer.trim() || path.basename(cwd);
76
- resolveAgentTargets(function (targets) { scaffold(name, targets); });
79
+ resolvePreset(function (selectedPreset) {
80
+ resolveAgentTargets(function (targets) { scaffold(name, selectedPreset, targets); });
81
+ });
82
+ });
83
+ }
84
+
85
+ /**
86
+ * Resolve preset from --preset flag or interactive prompt.
87
+ */
88
+ function resolvePreset(cb) {
89
+ if (presetFlag) return cb(presetFlag);
90
+ askPreset(cb);
91
+ }
92
+
93
+ /**
94
+ * Prompt user to select a methodology preset.
95
+ * @param {function} cb - Callback receiving the preset name string
96
+ */
97
+ function askPreset(cb) {
98
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
99
+ const defaultIdx = availablePresets.indexOf(configEngine.DEFAULT_PRESET);
100
+ console.log('');
101
+ console.log(' Methodology preset:');
102
+ availablePresets.forEach(function (p, i) {
103
+ const num = i + 1;
104
+ const marker = p === configEngine.DEFAULT_PRESET ? ' (default)' : '';
105
+ console.log(' ' + num + '. ' + p + marker);
106
+ });
107
+ rl.question(' Choice [' + (defaultIdx + 1) + ']: ', function (answer) {
108
+ rl.close();
109
+ const choice = (answer || '').trim();
110
+ if (!choice) return cb(configEngine.DEFAULT_PRESET);
111
+ const idx = parseInt(choice, 10);
112
+ if (idx >= 1 && idx <= availablePresets.length) return cb(availablePresets[idx - 1]);
113
+ // Allow typing the preset name directly
114
+ if (availablePresets.includes(choice)) return cb(choice);
115
+ console.error(' Invalid choice, using default: ' + configEngine.DEFAULT_PRESET);
116
+ return cb(configEngine.DEFAULT_PRESET);
77
117
  });
78
118
  }
79
119
 
@@ -113,7 +153,10 @@ function askAgentTargets(cb) {
113
153
  });
114
154
  }
115
155
 
116
- function scaffold(name, agentTargets) {
156
+ function scaffold(name, preset, agentTargets) {
157
+ // Set env so configEngine picks up the selected preset
158
+ process.env.MDBOARD_PRESET = preset;
159
+
117
160
  // Load preset config
118
161
  const cfg = configEngine.loadConfig(null);
119
162
  const structure = cfg.structure || {};
@@ -438,6 +438,9 @@ function buildFrontmatter(cfg, type, id, data) {
438
438
  fm[name] = data[name];
439
439
  } else if (def.default !== undefined) {
440
440
  fm[name] = def.default;
441
+ } else {
442
+ // Include all defined fields with empty values so the schema is always complete
443
+ fm[name] = emptyValueForType(def.type);
441
444
  }
442
445
  }
443
446
 
@@ -445,6 +448,16 @@ function buildFrontmatter(cfg, type, id, data) {
445
448
  return fm;
446
449
  }
447
450
 
451
+ /**
452
+ * Return an appropriate empty value for a field type.
453
+ */
454
+ function emptyValueForType(type) {
455
+ if (type === 'list') return [];
456
+ if (type === 'number') return null;
457
+ if (type === 'ref') return null;
458
+ return '';
459
+ }
460
+
448
461
  /**
449
462
  * Update an entity's markdown file.
450
463
  *