delimit-cli 3.13.3 → 3.14.1
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 +304 -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
|
@@ -5,6 +5,7 @@ const axios = require('axios');
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const { execSync, spawn } = require('child_process');
|
|
8
|
+
const os = require('os');
|
|
8
9
|
const chalk = require('chalk');
|
|
9
10
|
const inquirer = require('inquirer');
|
|
10
11
|
const DelimitAuthSetup = require('../lib/auth-setup');
|
|
@@ -1067,9 +1068,43 @@ program
|
|
|
1067
1068
|
return;
|
|
1068
1069
|
}
|
|
1069
1070
|
|
|
1071
|
+
// Step 2b: Compliance template selection (LED-258)
|
|
1072
|
+
let complianceTemplate = null;
|
|
1073
|
+
if (!options.yes) {
|
|
1074
|
+
try {
|
|
1075
|
+
const templateAns = await inquirer.prompt([{
|
|
1076
|
+
type: 'list',
|
|
1077
|
+
name: 'template',
|
|
1078
|
+
message: 'Compliance template (optional):',
|
|
1079
|
+
choices: [
|
|
1080
|
+
{ name: 'none — Standard governance only', value: 'none' },
|
|
1081
|
+
{ name: 'SOC2 — Service Organization Control evidence', value: 'soc2' },
|
|
1082
|
+
{ name: 'PCI-DSS — Payment card data protection', value: 'pci-dss' },
|
|
1083
|
+
{ name: 'HIPAA — Healthcare data safeguards', value: 'hipaa' },
|
|
1084
|
+
{ name: 'startup — Fast-moving team defaults', value: 'startup' },
|
|
1085
|
+
],
|
|
1086
|
+
default: 'none',
|
|
1087
|
+
}]);
|
|
1088
|
+
if (templateAns.template !== 'none') complianceTemplate = templateAns.template;
|
|
1089
|
+
} catch {}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1070
1092
|
// Step 3: Create policy file
|
|
1071
1093
|
fs.mkdirSync(configDir, { recursive: true });
|
|
1072
1094
|
fs.writeFileSync(policyFile, POLICY_PRESETS[preset]);
|
|
1095
|
+
|
|
1096
|
+
// Write compliance template config if selected
|
|
1097
|
+
if (complianceTemplate) {
|
|
1098
|
+
const templateConfig = {
|
|
1099
|
+
soc2: { evidence_required: true, audit_trail: true, change_approval: true, retention_days: 365 },
|
|
1100
|
+
'pci-dss': { evidence_required: true, audit_trail: true, change_approval: true, secret_scanning: true, retention_days: 365 },
|
|
1101
|
+
hipaa: { evidence_required: true, audit_trail: true, change_approval: true, phi_detection: true, retention_days: 2190 },
|
|
1102
|
+
startup: { evidence_required: false, audit_trail: true, change_approval: false, retention_days: 90 },
|
|
1103
|
+
};
|
|
1104
|
+
const tmplFile = path.join(configDir, 'compliance.json');
|
|
1105
|
+
fs.writeFileSync(tmplFile, JSON.stringify({ template: complianceTemplate, ...templateConfig[complianceTemplate] }, null, 2));
|
|
1106
|
+
console.log(chalk.green(` Created .delimit/compliance.json (${complianceTemplate})`));
|
|
1107
|
+
}
|
|
1073
1108
|
console.log(chalk.green(` Created .delimit/policies.yml (${preset})`));
|
|
1074
1109
|
|
|
1075
1110
|
// Step 4: Add GitHub Action workflow if spec found + GitHub CI
|
|
@@ -1130,6 +1165,69 @@ jobs:
|
|
|
1130
1165
|
}
|
|
1131
1166
|
}
|
|
1132
1167
|
|
|
1168
|
+
// Step 4b: Add scheduled drift monitoring workflow (LED-260)
|
|
1169
|
+
if (specPath && ciProvider === 'github') {
|
|
1170
|
+
const driftWorkflowFile = path.join(projectDir, '.github', 'workflows', 'api-drift-monitor.yml');
|
|
1171
|
+
if (!fs.existsSync(driftWorkflowFile)) {
|
|
1172
|
+
let writeDrift = false;
|
|
1173
|
+
if (!options.yes) {
|
|
1174
|
+
try {
|
|
1175
|
+
const driftAns = await inquirer.prompt([{
|
|
1176
|
+
type: 'confirm',
|
|
1177
|
+
name: 'addDrift',
|
|
1178
|
+
message: 'Add weekly drift monitoring workflow?',
|
|
1179
|
+
default: true,
|
|
1180
|
+
}]);
|
|
1181
|
+
writeDrift = driftAns.addDrift;
|
|
1182
|
+
} catch {}
|
|
1183
|
+
}
|
|
1184
|
+
if (writeDrift) {
|
|
1185
|
+
try {
|
|
1186
|
+
const driftContent = `name: API Drift Monitor
|
|
1187
|
+
on:
|
|
1188
|
+
schedule:
|
|
1189
|
+
- cron: '17 9 * * 1' # Weekly on Monday at 9:17 AM UTC
|
|
1190
|
+
workflow_dispatch: {}
|
|
1191
|
+
|
|
1192
|
+
permissions:
|
|
1193
|
+
contents: read
|
|
1194
|
+
issues: write
|
|
1195
|
+
|
|
1196
|
+
jobs:
|
|
1197
|
+
drift-check:
|
|
1198
|
+
runs-on: ubuntu-latest
|
|
1199
|
+
steps:
|
|
1200
|
+
- uses: actions/checkout@v4
|
|
1201
|
+
- uses: actions/setup-python@v4
|
|
1202
|
+
with:
|
|
1203
|
+
python-version: '3.10'
|
|
1204
|
+
- run: pip install pyyaml 2>/dev/null
|
|
1205
|
+
- name: Check for API drift
|
|
1206
|
+
run: |
|
|
1207
|
+
npx delimit-cli lint ${specPath} ${specPath} --baseline
|
|
1208
|
+
echo "Drift check complete"
|
|
1209
|
+
- name: Create issue on drift
|
|
1210
|
+
if: failure()
|
|
1211
|
+
uses: actions/github-script@v6
|
|
1212
|
+
with:
|
|
1213
|
+
script: |
|
|
1214
|
+
await github.rest.issues.create({
|
|
1215
|
+
owner: context.repo.owner,
|
|
1216
|
+
repo: context.repo.repo,
|
|
1217
|
+
title: 'API Drift Detected — Governance Review Needed',
|
|
1218
|
+
body: 'The weekly drift monitor detected changes to the API spec that have not been reviewed through governance. Run delimit lint to review.',
|
|
1219
|
+
labels: ['api-governance', 'drift'],
|
|
1220
|
+
});
|
|
1221
|
+
`;
|
|
1222
|
+
fs.writeFileSync(driftWorkflowFile, driftContent);
|
|
1223
|
+
console.log(chalk.green(' Created .github/workflows/api-drift-monitor.yml'));
|
|
1224
|
+
} catch (err) {
|
|
1225
|
+
console.log(chalk.yellow(` Could not write drift workflow: ${err.message}`));
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1133
1231
|
// Step 5: Run first lint to show immediate value
|
|
1134
1232
|
console.log('');
|
|
1135
1233
|
if (specPath) {
|
|
@@ -1182,9 +1280,50 @@ jobs:
|
|
|
1182
1280
|
}
|
|
1183
1281
|
}
|
|
1184
1282
|
|
|
1283
|
+
// Step 6: Save first evidence event (LED-258)
|
|
1284
|
+
const evidenceDir = path.join(configDir, 'evidence');
|
|
1285
|
+
fs.mkdirSync(evidenceDir, { recursive: true });
|
|
1286
|
+
const evidenceEvent = {
|
|
1287
|
+
id: `EVD-${Date.now().toString(36)}`,
|
|
1288
|
+
ts: new Date().toISOString(),
|
|
1289
|
+
type: 'governance_init',
|
|
1290
|
+
tool: 'delimit_init',
|
|
1291
|
+
model: 'cli',
|
|
1292
|
+
status: 'pass',
|
|
1293
|
+
summary: `Governance initialized with ${preset} preset`,
|
|
1294
|
+
detail: [
|
|
1295
|
+
`Project: ${projectName}`,
|
|
1296
|
+
frameworkLabel ? `Framework: ${frameworkLabel}` : null,
|
|
1297
|
+
specPath ? `Spec: ${specPath}` : 'Mode: Zero-Spec',
|
|
1298
|
+
`Preset: ${preset}`,
|
|
1299
|
+
ciProvider !== 'none' ? `CI: ${ciProvider}` : null,
|
|
1300
|
+
].filter(Boolean).join('\n'),
|
|
1301
|
+
venture: projectName,
|
|
1302
|
+
};
|
|
1303
|
+
try {
|
|
1304
|
+
const evidenceFile = path.join(evidenceDir, 'events.jsonl');
|
|
1305
|
+
fs.appendFileSync(evidenceFile, JSON.stringify(evidenceEvent) + '\n');
|
|
1306
|
+
console.log(chalk.green(' Evidence recorded — first governance event saved'));
|
|
1307
|
+
} catch {}
|
|
1308
|
+
|
|
1309
|
+
// Step 7: Show gate status (LED-258)
|
|
1310
|
+
console.log(chalk.bold('\n Governance Gates:'));
|
|
1311
|
+
const gates = [
|
|
1312
|
+
{ name: 'API Lint', status: specPath || ['fastapi', 'nestjs', 'express'].includes(framework) ? 'active' : 'inactive', chain: 'semver → gov_evaluate' },
|
|
1313
|
+
{ name: 'Security Audit', status: 'ready', chain: 'evidence_collect → notify' },
|
|
1314
|
+
{ name: 'Deploy Plan', status: 'ready', chain: 'security_audit' },
|
|
1315
|
+
{ name: 'Release Validate', status: 'ready', chain: 'evidence_collect → notify → ledger' },
|
|
1316
|
+
];
|
|
1317
|
+
for (const gate of gates) {
|
|
1318
|
+
const icon = gate.status === 'active' ? chalk.green('●') : gate.status === 'ready' ? chalk.yellow('○') : chalk.gray('○');
|
|
1319
|
+
const statusLabel = gate.status === 'active' ? chalk.green('active') : gate.status === 'ready' ? chalk.yellow('ready') : chalk.gray('inactive');
|
|
1320
|
+
console.log(` ${icon} ${chalk.bold(gate.name)} ${chalk.gray('→')} ${chalk.gray(gate.chain)} ${chalk.gray('(')}${statusLabel}${chalk.gray(')')}`);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1185
1323
|
// Summary
|
|
1186
1324
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
1187
|
-
console.log(chalk.bold(`\n Setup complete in ${elapsed}s
|
|
1325
|
+
console.log(chalk.bold(`\n Setup complete in ${elapsed}s`));
|
|
1326
|
+
console.log(chalk.gray(` Evidence saved to .delimit/evidence/events.jsonl\n`));
|
|
1188
1327
|
console.log(' Next steps:');
|
|
1189
1328
|
if (specPath) {
|
|
1190
1329
|
console.log(` ${chalk.bold('delimit lint')} ${specPath} ${specPath} — lint on every PR`);
|
|
@@ -1196,6 +1335,170 @@ jobs:
|
|
|
1196
1335
|
console.log('');
|
|
1197
1336
|
});
|
|
1198
1337
|
|
|
1338
|
+
// Demo command — prove governance value in 5 minutes (LED-262)
|
|
1339
|
+
program
|
|
1340
|
+
.command('demo')
|
|
1341
|
+
.description('Run a self-contained governance demo — proves value in under 5 minutes')
|
|
1342
|
+
.action(async () => {
|
|
1343
|
+
const tmpDir = path.join(os.tmpdir(), `delimit-demo-${Date.now()}`);
|
|
1344
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
1345
|
+
|
|
1346
|
+
console.log(chalk.bold('\n Delimit Governance Demo\n'));
|
|
1347
|
+
console.log(chalk.gray(` Working in ${tmpDir}\n`));
|
|
1348
|
+
|
|
1349
|
+
// Step 1: Create a sample API spec
|
|
1350
|
+
console.log(chalk.bold(' Step 1: Creating sample API spec...'));
|
|
1351
|
+
const baseSpec = {
|
|
1352
|
+
openapi: '3.0.3',
|
|
1353
|
+
info: { title: 'Pet Store API', version: '1.0.0' },
|
|
1354
|
+
paths: {
|
|
1355
|
+
'/pets': {
|
|
1356
|
+
get: {
|
|
1357
|
+
summary: 'List all pets',
|
|
1358
|
+
operationId: 'listPets',
|
|
1359
|
+
parameters: [
|
|
1360
|
+
{ name: 'limit', in: 'query', required: false, schema: { type: 'integer' } },
|
|
1361
|
+
],
|
|
1362
|
+
responses: { '200': { description: 'A list of pets', content: { 'application/json': { schema: { type: 'array', items: { '$ref': '#/components/schemas/Pet' } } } } } },
|
|
1363
|
+
},
|
|
1364
|
+
post: {
|
|
1365
|
+
summary: 'Create a pet',
|
|
1366
|
+
operationId: 'createPet',
|
|
1367
|
+
requestBody: { content: { 'application/json': { schema: { '$ref': '#/components/schemas/Pet' } } } },
|
|
1368
|
+
responses: { '201': { description: 'Pet created' } },
|
|
1369
|
+
},
|
|
1370
|
+
},
|
|
1371
|
+
'/pets/{petId}': {
|
|
1372
|
+
get: {
|
|
1373
|
+
summary: 'Get a pet by ID',
|
|
1374
|
+
operationId: 'showPetById',
|
|
1375
|
+
parameters: [{ name: 'petId', in: 'path', required: true, schema: { type: 'string' } }],
|
|
1376
|
+
responses: { '200': { description: 'A pet', content: { 'application/json': { schema: { '$ref': '#/components/schemas/Pet' } } } } },
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
components: {
|
|
1381
|
+
schemas: {
|
|
1382
|
+
Pet: {
|
|
1383
|
+
type: 'object',
|
|
1384
|
+
required: ['id', 'name'],
|
|
1385
|
+
properties: {
|
|
1386
|
+
id: { type: 'integer', format: 'int64' },
|
|
1387
|
+
name: { type: 'string' },
|
|
1388
|
+
tag: { type: 'string' },
|
|
1389
|
+
},
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1392
|
+
},
|
|
1393
|
+
};
|
|
1394
|
+
|
|
1395
|
+
const baseSpecPath = path.join(tmpDir, 'openapi-v1.yaml');
|
|
1396
|
+
fs.writeFileSync(baseSpecPath, yaml.dump(baseSpec));
|
|
1397
|
+
console.log(chalk.green(' Created openapi-v1.yaml (3 endpoints, 1 schema)\n'));
|
|
1398
|
+
|
|
1399
|
+
// Step 2: Introduce breaking changes
|
|
1400
|
+
console.log(chalk.bold(' Step 2: Introducing breaking changes...'));
|
|
1401
|
+
const changedSpec = JSON.parse(JSON.stringify(baseSpec));
|
|
1402
|
+
changedSpec.info.version = '2.0.0';
|
|
1403
|
+
|
|
1404
|
+
// Breaking: remove endpoint
|
|
1405
|
+
delete changedSpec.paths['/pets/{petId}'];
|
|
1406
|
+
// Breaking: add required parameter
|
|
1407
|
+
changedSpec.paths['/pets'].get.parameters.push(
|
|
1408
|
+
{ name: 'owner_id', in: 'query', required: true, schema: { type: 'string' } }
|
|
1409
|
+
);
|
|
1410
|
+
// Breaking: remove response field
|
|
1411
|
+
delete changedSpec.components.schemas.Pet.properties.tag;
|
|
1412
|
+
// Non-breaking: add endpoint
|
|
1413
|
+
changedSpec.paths['/pets/search'] = {
|
|
1414
|
+
get: {
|
|
1415
|
+
summary: 'Search pets',
|
|
1416
|
+
operationId: 'searchPets',
|
|
1417
|
+
parameters: [{ name: 'q', in: 'query', required: true, schema: { type: 'string' } }],
|
|
1418
|
+
responses: { '200': { description: 'Search results' } },
|
|
1419
|
+
},
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
const changedSpecPath = path.join(tmpDir, 'openapi-v2.yaml');
|
|
1423
|
+
fs.writeFileSync(changedSpecPath, yaml.dump(changedSpec));
|
|
1424
|
+
console.log(chalk.red(' Removed: GET /pets/{petId}'));
|
|
1425
|
+
console.log(chalk.red(' Added required param: owner_id on GET /pets'));
|
|
1426
|
+
console.log(chalk.red(' Removed field: Pet.tag'));
|
|
1427
|
+
console.log(chalk.green(' Added: GET /pets/search'));
|
|
1428
|
+
console.log('');
|
|
1429
|
+
|
|
1430
|
+
// Step 3: Run Delimit lint
|
|
1431
|
+
console.log(chalk.bold(' Step 3: Running governance check...\n'));
|
|
1432
|
+
try {
|
|
1433
|
+
const result = apiEngine.lint(baseSpecPath, changedSpecPath, { policy: 'strict' });
|
|
1434
|
+
|
|
1435
|
+
if (result && result.summary) {
|
|
1436
|
+
const s = result.summary;
|
|
1437
|
+
const breaking = s.breaking || s.breaking_changes || 0;
|
|
1438
|
+
const total = s.total || s.total_changes || 0;
|
|
1439
|
+
const safe = total - breaking;
|
|
1440
|
+
|
|
1441
|
+
if (breaking > 0) {
|
|
1442
|
+
console.log(chalk.red.bold(` BLOCKED — ${breaking} breaking change(s) detected\n`));
|
|
1443
|
+
} else {
|
|
1444
|
+
console.log(chalk.green.bold(` PASSED — No breaking changes\n`));
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// Show violations
|
|
1448
|
+
const violations = result.violations || [];
|
|
1449
|
+
if (violations.length > 0) {
|
|
1450
|
+
console.log(chalk.bold(' Violations:'));
|
|
1451
|
+
violations.forEach((v, i) => {
|
|
1452
|
+
const icon = v.severity === 'error' ? chalk.red(' BLOCK') : chalk.yellow(' WARN ');
|
|
1453
|
+
console.log(` ${icon} ${v.message}`);
|
|
1454
|
+
if (v.path) console.log(chalk.gray(` ${v.path}`));
|
|
1455
|
+
});
|
|
1456
|
+
console.log('');
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
// Semver
|
|
1460
|
+
if (result.semver) {
|
|
1461
|
+
console.log(` Semver: ${chalk.bold(result.semver.bump?.toUpperCase() || 'MAJOR')}`);
|
|
1462
|
+
if (result.semver.next_version) {
|
|
1463
|
+
console.log(` Next version: ${chalk.bold(result.semver.next_version)}`);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
// Show safe changes
|
|
1468
|
+
if (safe > 0) {
|
|
1469
|
+
console.log(chalk.green(`\n ${safe} additive change(s) also detected`));
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
} catch (err) {
|
|
1473
|
+
console.log(chalk.yellow(` Lint error: ${err.message}`));
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// Step 4: Show governance gates
|
|
1477
|
+
console.log(chalk.bold('\n Governance Gates:'));
|
|
1478
|
+
console.log(` ${chalk.red('X')} API Lint ${chalk.gray('→ semver → gov_evaluate')}`);
|
|
1479
|
+
console.log(` ${chalk.red('X')} Policy Compliance ${chalk.gray('→ evidence_collect')}`);
|
|
1480
|
+
console.log(` ${chalk.green('+')} Security Audit ${chalk.gray('→ evidence_collect → notify')}`);
|
|
1481
|
+
console.log(` ${chalk.red('X')} Deploy Readiness ${chalk.gray('→ deploy_plan → security_audit')}`);
|
|
1482
|
+
console.log(chalk.red.bold('\n Deploy BLOCKED until all gates pass.\n'));
|
|
1483
|
+
|
|
1484
|
+
// Step 5: Show what would happen with the fix
|
|
1485
|
+
console.log(chalk.bold(' What Delimit does:'));
|
|
1486
|
+
console.log(chalk.gray(' 1. Detects the 3 breaking changes automatically'));
|
|
1487
|
+
console.log(chalk.gray(' 2. Evaluates against your policy (strict/default/relaxed)'));
|
|
1488
|
+
console.log(chalk.gray(' 3. Blocks the deploy via governance gates'));
|
|
1489
|
+
console.log(chalk.gray(' 4. Records evidence for audit trail'));
|
|
1490
|
+
console.log(chalk.gray(' 5. Posts remediation guide on the PR'));
|
|
1491
|
+
console.log(chalk.gray(' 6. Tracks in the ledger for cross-model continuity'));
|
|
1492
|
+
|
|
1493
|
+
console.log(chalk.bold('\n Try it on your project:'));
|
|
1494
|
+
console.log(` ${chalk.green('npx delimit-cli init')} — set up governance`);
|
|
1495
|
+
console.log(` ${chalk.green('npx delimit-cli lint')} — lint your API spec`);
|
|
1496
|
+
console.log(` ${chalk.green('npx delimit-cli setup')} — configure AI assistants\n`);
|
|
1497
|
+
|
|
1498
|
+
// Cleanup
|
|
1499
|
+
try { fs.rmSync(tmpDir, { recursive: true }); } catch {}
|
|
1500
|
+
});
|
|
1501
|
+
|
|
1199
1502
|
// Doctor command — verify setup is correct
|
|
1200
1503
|
program
|
|
1201
1504
|
.command('doctor')
|
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\`
|