Closing the intent-to-code chasm - specification-driven development with BDD verification chain
Overall
score
96%
Does it follow best practices?
Validation for skill structure
'use strict';
const fs = require('fs');
const path = require('path');
const { parseBugs, parseTasks } = require('./parser');
const SEVERITY_ORDER = { critical: 0, high: 1, medium: 2, low: 3 };
/**
* Resolve a GitHub issue reference like "#13" to a full URL.
*
* @param {string|null} issueRef - Issue reference (e.g., "#13") or null
* @param {string|null} repoUrl - Repository URL from git remote or null
* @returns {string|null} Full URL or null
*/
function resolveGitHubIssueUrl(issueRef, repoUrl) {
if (!issueRef || !repoUrl) return null;
// Skip sentinel values
if (/^_\(/.test(issueRef)) return null;
// Extract issue number
const numMatch = issueRef.match(/#(\d+)/);
if (!numMatch) return null;
const issueNumber = numMatch[1];
// Normalize repo URL
let baseUrl = repoUrl;
// Handle SSH format: git@github.com:user/repo.git
const sshMatch = baseUrl.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
if (sshMatch) {
baseUrl = `https://${sshMatch[1]}/${sshMatch[2]}`;
}
// Strip trailing .git
baseUrl = baseUrl.replace(/\.git$/, '');
return `${baseUrl}/issues/${issueNumber}`;
}
/**
* Compute the bugs state for a feature.
* Reads bugs.md and tasks.md, cross-references fix tasks by [BUG-NNN] tag.
*
* @param {string} projectPath - Path to the project root
* @param {string} featureId - Feature directory name (e.g., "009-bugs-tab")
* @returns {{exists: boolean, bugs: Array, orphanedTasks: Array, summary: Object, repoUrl: string|null}}
*/
function computeBugsState(projectPath, featureId) {
const featureDir = path.join(projectPath, 'specs', featureId);
const bugsPath = path.join(featureDir, 'bugs.md');
const tasksPath = path.join(featureDir, 'tasks.md');
const emptySummary = {
total: 0,
open: 0,
fixed: 0,
highestOpenSeverity: null,
bySeverity: { critical: 0, high: 0, medium: 0, low: 0 }
};
if (!fs.existsSync(bugsPath)) {
return { exists: false, bugs: [], orphanedTasks: [], summary: emptySummary, repoUrl: null };
}
const bugsContent = fs.readFileSync(bugsPath, 'utf-8');
const bugs = parseBugs(bugsContent);
// Parse tasks for fix task cross-referencing
const tasksContent = fs.existsSync(tasksPath) ? fs.readFileSync(tasksPath, 'utf-8') : '';
const allTasks = parseTasks(tasksContent);
const bugFixTasks = allTasks.filter(t => t.isBugFix && t.bugTag);
// Build lookup: BUG-NNN -> [task, ...]
const tasksByBug = {};
for (const task of bugFixTasks) {
if (!tasksByBug[task.bugTag]) tasksByBug[task.bugTag] = [];
tasksByBug[task.bugTag].push(task);
}
// Track which bug IDs exist
const bugIds = new Set(bugs.map(b => b.id));
// Enrich bugs with fix tasks
for (const bug of bugs) {
const tasks = tasksByBug[bug.id] || [];
bug.fixTasks = {
total: tasks.length,
checked: tasks.filter(t => t.checked).length,
tasks: tasks.map(t => ({
id: t.id,
description: t.description,
checked: t.checked
}))
};
}
// Sort bugs: severity descending (critical first), then ID ascending
bugs.sort((a, b) => {
const sevA = SEVERITY_ORDER[a.severity] !== undefined ? SEVERITY_ORDER[a.severity] : 3;
const sevB = SEVERITY_ORDER[b.severity] !== undefined ? SEVERITY_ORDER[b.severity] : 3;
const sevDiff = sevA - sevB;
if (sevDiff !== 0) return sevDiff;
return a.id.localeCompare(b.id);
});
// Detect orphaned tasks (T-B tasks referencing non-existent BUG-NNN)
const orphanedTasks = bugFixTasks
.filter(t => !bugIds.has(t.bugTag))
.map(t => ({ id: t.id, bugTag: t.bugTag, description: t.description, checked: t.checked }));
// Compute summary
const openBugs = bugs.filter(b => b.status !== 'fixed');
const fixedBugs = bugs.filter(b => b.status === 'fixed');
const bySeverity = { critical: 0, high: 0, medium: 0, low: 0 };
for (const bug of openBugs) {
if (bySeverity.hasOwnProperty(bug.severity)) {
bySeverity[bug.severity]++;
}
}
let highestOpenSeverity = null;
for (const sev of ['critical', 'high', 'medium', 'low']) {
if (bySeverity[sev] > 0) {
highestOpenSeverity = sev;
break;
}
}
// Try to get repo URL from git remote
let repoUrl = null;
try {
const { execSync } = require('child_process');
repoUrl = execSync('git remote get-url origin', {
cwd: projectPath,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe']
}).trim();
// Strip .git suffix
repoUrl = repoUrl.replace(/\.git$/, '');
// Handle SSH format
const sshMatch = repoUrl.match(/^git@([^:]+):(.+)$/);
if (sshMatch) {
repoUrl = `https://${sshMatch[1]}/${sshMatch[2]}`;
}
} catch {
// No git remote — repoUrl stays null
}
return {
exists: true,
bugs,
orphanedTasks,
summary: {
total: bugs.length,
open: openBugs.length,
fixed: fixedBugs.length,
highestOpenSeverity,
bySeverity
},
repoUrl
};
}
module.exports = { computeBugsState, resolveGitHubIssueUrl };Install with Tessl CLI
npx tessl i tessl-labs/intent-integrity-kit@2.3.5rules
skills
iikit-00-constitution
scripts
iikit-01-specify
iikit-02-clarify
iikit-03-plan
iikit-04-checklist
scripts
dashboard
iikit-05-testify
iikit-06-tasks
iikit-07-analyze
iikit-08-implement
iikit-09-taskstoissues
iikit-bugfix
scripts
iikit-core
scripts
bash
dashboard
powershell