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.
- package/bin/delimit-cli.js +139 -1
- package/bin/delimit-setup.js +10 -4
- package/gateway/ai/inbox_daemon.py +623 -0
- package/gateway/ai/ledger_manager.py +88 -19
- package/gateway/ai/notify.py +975 -0
- package/gateway/ai/server.py +3570 -426
- package/gateway/ai/social.py +504 -0
- package/gateway/ai/tool_metadata.py +201 -0
- package/lib/cross-model-hooks.js +173 -43
- package/package.json +1 -1
- package/scripts/crosspost_devto.py +304 -0
package/bin/delimit-cli.js
CHANGED
|
@@ -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
|
|
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`);
|
package/bin/delimit-setup.js
CHANGED
|
@@ -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
|
|
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" ]
|
|
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.
|
|
814
|
-
4. If
|
|
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\`
|