delimit-cli 3.13.3 → 3.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.
@@ -1067,9 +1067,43 @@ program
1067
1067
  return;
1068
1068
  }
1069
1069
 
1070
+ // Step 2b: Compliance template selection (LED-258)
1071
+ let complianceTemplate = null;
1072
+ if (!options.yes) {
1073
+ try {
1074
+ const templateAns = await inquirer.prompt([{
1075
+ type: 'list',
1076
+ name: 'template',
1077
+ message: 'Compliance template (optional):',
1078
+ choices: [
1079
+ { name: 'none — Standard governance only', value: 'none' },
1080
+ { name: 'SOC2 — Service Organization Control evidence', value: 'soc2' },
1081
+ { name: 'PCI-DSS — Payment card data protection', value: 'pci-dss' },
1082
+ { name: 'HIPAA — Healthcare data safeguards', value: 'hipaa' },
1083
+ { name: 'startup — Fast-moving team defaults', value: 'startup' },
1084
+ ],
1085
+ default: 'none',
1086
+ }]);
1087
+ if (templateAns.template !== 'none') complianceTemplate = templateAns.template;
1088
+ } catch {}
1089
+ }
1090
+
1070
1091
  // Step 3: Create policy file
1071
1092
  fs.mkdirSync(configDir, { recursive: true });
1072
1093
  fs.writeFileSync(policyFile, POLICY_PRESETS[preset]);
1094
+
1095
+ // Write compliance template config if selected
1096
+ if (complianceTemplate) {
1097
+ const templateConfig = {
1098
+ soc2: { evidence_required: true, audit_trail: true, change_approval: true, retention_days: 365 },
1099
+ 'pci-dss': { evidence_required: true, audit_trail: true, change_approval: true, secret_scanning: true, retention_days: 365 },
1100
+ hipaa: { evidence_required: true, audit_trail: true, change_approval: true, phi_detection: true, retention_days: 2190 },
1101
+ startup: { evidence_required: false, audit_trail: true, change_approval: false, retention_days: 90 },
1102
+ };
1103
+ const tmplFile = path.join(configDir, 'compliance.json');
1104
+ fs.writeFileSync(tmplFile, JSON.stringify({ template: complianceTemplate, ...templateConfig[complianceTemplate] }, null, 2));
1105
+ console.log(chalk.green(` Created .delimit/compliance.json (${complianceTemplate})`));
1106
+ }
1073
1107
  console.log(chalk.green(` Created .delimit/policies.yml (${preset})`));
1074
1108
 
1075
1109
  // Step 4: Add GitHub Action workflow if spec found + GitHub CI
@@ -1130,6 +1164,69 @@ jobs:
1130
1164
  }
1131
1165
  }
1132
1166
 
1167
+ // Step 4b: Add scheduled drift monitoring workflow (LED-260)
1168
+ if (specPath && ciProvider === 'github') {
1169
+ const driftWorkflowFile = path.join(projectDir, '.github', 'workflows', 'api-drift-monitor.yml');
1170
+ if (!fs.existsSync(driftWorkflowFile)) {
1171
+ let writeDrift = false;
1172
+ if (!options.yes) {
1173
+ try {
1174
+ const driftAns = await inquirer.prompt([{
1175
+ type: 'confirm',
1176
+ name: 'addDrift',
1177
+ message: 'Add weekly drift monitoring workflow?',
1178
+ default: true,
1179
+ }]);
1180
+ writeDrift = driftAns.addDrift;
1181
+ } catch {}
1182
+ }
1183
+ if (writeDrift) {
1184
+ try {
1185
+ const driftContent = `name: API Drift Monitor
1186
+ on:
1187
+ schedule:
1188
+ - cron: '17 9 * * 1' # Weekly on Monday at 9:17 AM UTC
1189
+ workflow_dispatch: {}
1190
+
1191
+ permissions:
1192
+ contents: read
1193
+ issues: write
1194
+
1195
+ jobs:
1196
+ drift-check:
1197
+ runs-on: ubuntu-latest
1198
+ steps:
1199
+ - uses: actions/checkout@v4
1200
+ - uses: actions/setup-python@v4
1201
+ with:
1202
+ python-version: '3.10'
1203
+ - run: pip install pyyaml 2>/dev/null
1204
+ - name: Check for API drift
1205
+ run: |
1206
+ npx delimit-cli lint ${specPath} ${specPath} --baseline
1207
+ echo "Drift check complete"
1208
+ - name: Create issue on drift
1209
+ if: failure()
1210
+ uses: actions/github-script@v6
1211
+ with:
1212
+ script: |
1213
+ await github.rest.issues.create({
1214
+ owner: context.repo.owner,
1215
+ repo: context.repo.repo,
1216
+ title: 'API Drift Detected — Governance Review Needed',
1217
+ body: 'The weekly drift monitor detected changes to the API spec that have not been reviewed through governance. Run delimit lint to review.',
1218
+ labels: ['api-governance', 'drift'],
1219
+ });
1220
+ `;
1221
+ fs.writeFileSync(driftWorkflowFile, driftContent);
1222
+ console.log(chalk.green(' Created .github/workflows/api-drift-monitor.yml'));
1223
+ } catch (err) {
1224
+ console.log(chalk.yellow(` Could not write drift workflow: ${err.message}`));
1225
+ }
1226
+ }
1227
+ }
1228
+ }
1229
+
1133
1230
  // Step 5: Run first lint to show immediate value
1134
1231
  console.log('');
1135
1232
  if (specPath) {
@@ -1182,9 +1279,50 @@ jobs:
1182
1279
  }
1183
1280
  }
1184
1281
 
1282
+ // Step 6: Save first evidence event (LED-258)
1283
+ const evidenceDir = path.join(configDir, 'evidence');
1284
+ fs.mkdirSync(evidenceDir, { recursive: true });
1285
+ const evidenceEvent = {
1286
+ id: `EVD-${Date.now().toString(36)}`,
1287
+ ts: new Date().toISOString(),
1288
+ type: 'governance_init',
1289
+ tool: 'delimit_init',
1290
+ model: 'cli',
1291
+ status: 'pass',
1292
+ summary: `Governance initialized with ${preset} preset`,
1293
+ detail: [
1294
+ `Project: ${projectName}`,
1295
+ frameworkLabel ? `Framework: ${frameworkLabel}` : null,
1296
+ specPath ? `Spec: ${specPath}` : 'Mode: Zero-Spec',
1297
+ `Preset: ${preset}`,
1298
+ ciProvider !== 'none' ? `CI: ${ciProvider}` : null,
1299
+ ].filter(Boolean).join('\n'),
1300
+ venture: projectName,
1301
+ };
1302
+ try {
1303
+ const evidenceFile = path.join(evidenceDir, 'events.jsonl');
1304
+ fs.appendFileSync(evidenceFile, JSON.stringify(evidenceEvent) + '\n');
1305
+ console.log(chalk.green(' Evidence recorded — first governance event saved'));
1306
+ } catch {}
1307
+
1308
+ // Step 7: Show gate status (LED-258)
1309
+ console.log(chalk.bold('\n Governance Gates:'));
1310
+ const gates = [
1311
+ { name: 'API Lint', status: specPath || ['fastapi', 'nestjs', 'express'].includes(framework) ? 'active' : 'inactive', chain: 'semver → gov_evaluate' },
1312
+ { name: 'Security Audit', status: 'ready', chain: 'evidence_collect → notify' },
1313
+ { name: 'Deploy Plan', status: 'ready', chain: 'security_audit' },
1314
+ { name: 'Release Validate', status: 'ready', chain: 'evidence_collect → notify → ledger' },
1315
+ ];
1316
+ for (const gate of gates) {
1317
+ const icon = gate.status === 'active' ? chalk.green('●') : gate.status === 'ready' ? chalk.yellow('○') : chalk.gray('○');
1318
+ const statusLabel = gate.status === 'active' ? chalk.green('active') : gate.status === 'ready' ? chalk.yellow('ready') : chalk.gray('inactive');
1319
+ console.log(` ${icon} ${chalk.bold(gate.name)} ${chalk.gray('→')} ${chalk.gray(gate.chain)} ${chalk.gray('(')}${statusLabel}${chalk.gray(')')}`);
1320
+ }
1321
+
1185
1322
  // Summary
1186
1323
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
1187
- console.log(chalk.bold(`\n Setup complete in ${elapsed}s\n`));
1324
+ console.log(chalk.bold(`\n Setup complete in ${elapsed}s`));
1325
+ console.log(chalk.gray(` Evidence saved to .delimit/evidence/events.jsonl\n`));
1188
1326
  console.log(' Next steps:');
1189
1327
  if (specPath) {
1190
1328
  console.log(` ${chalk.bold('delimit lint')} ${specPath} ${specPath} — lint on every PR`);
@@ -290,7 +290,7 @@ async function main() {
290
290
  }
291
291
  // Add governance instructions
292
292
  if (!geminiConfig.customInstructions || !geminiConfig.customInstructions.includes('delimit_ledger_context')) {
293
- geminiConfig.customInstructions = 'Delimit MCP is installed. On every session start, call delimit_ledger_context to check for open tasks. If new project, call delimit_scan. Track all work via the ledger.';
293
+ geminiConfig.customInstructions = 'Delimit MCP is installed. On every session start: (1) call delimit_ledger_context for open tasks, (2) call delimit_gov_health, (3) call delimit_inbox_daemon(action="start") to start email polling. If new project, call delimit_scan. Track all work via the ledger.';
294
294
  fs.writeFileSync(GEMINI_CONFIG, JSON.stringify(geminiConfig, null, 2));
295
295
  }
296
296
  } catch (e) {
@@ -537,7 +537,12 @@ if [ "$DELIMIT_WRAPPED" = "true" ] || [ ! -t 1 ]; then
537
537
  fi
538
538
  DELIMIT_HOME="\${DELIMIT_HOME:-$HOME/.delimit}"
539
539
  TOOL_COUNT="0"
540
- [ -f "$DELIMIT_HOME/server/ai/server.py" ] && TOOL_COUNT=$(grep -c '@mcp.tool' "$DELIMIT_HOME/server/ai/server.py" 2>/dev/null || echo "0")
540
+ if [ -f "$DELIMIT_HOME/server/ai/server.py" ]; then
541
+ TOTAL=$(grep -c '@mcp.tool' "$DELIMIT_HOME/server/ai/server.py" 2>/dev/null || echo "0")
542
+ OPS=$(grep -c '@_ops_pack_tool' "$DELIMIT_HOME/server/ai/server.py" 2>/dev/null || echo "0")
543
+ INTERNAL=$(grep -c '@_internal_tool' "$DELIMIT_HOME/server/ai/server.py" 2>/dev/null || echo "0")
544
+ TOOL_COUNT=$((TOTAL - OPS - INTERNAL))
545
+ fi
541
546
  echo ""
542
547
  printf " \${PURPLE}\${BOLD} ____ ________ ______ _____________\${RESET}\\n"
543
548
  printf " \${PURPLE}\${BOLD} / __ \\\\/ ____/ / / _/ |/ / _/_ __/\${RESET}\\n"
@@ -810,8 +815,9 @@ Unify all AI coding assistants with persistent context, governance, and multi-mo
810
815
  ## On every session start:
811
816
  1. Call \`delimit_ledger_context\` to check for open tasks
812
817
  2. Call \`delimit_gov_health\` to check governance status
813
- 3. If returning user, summarize what's pending
814
- 4. If new project, call \`delimit_scan\` to discover what Delimit can do
818
+ 3. Call \`delimit_inbox_daemon(action="start")\` to start email polling — ALL venture inboxes route through this. Owner approves/adjusts/denies via email reply, same as being logged in.
819
+ 4. If returning user, summarize what's pending
820
+ 5. If new project, call \`delimit_scan\` to discover what Delimit can do
815
821
 
816
822
  ## After editing code:
817
823
  - After editing UI/CSS: call \`delimit_design_validate_responsive\`