aiwg
Version:
Cognitive architecture for AI-augmented software development with structured memory, ensemble validation, and closed-loop correction. FAIR-aligned artifacts, 84% cost reduction via human-in-the-loop, standards adopted by 100+ organizations.
237 lines (198 loc) • 6.17 kB
JavaScript
/**
* AIWG Session Naming Hook
*
* Auto-names sessions based on AIWG workflow context.
*
* Research Foundation:
* - Claude Code 2.0.64: Named sessions with /rename and /resume
* - REF-001: Workflow state persistence for recovery
*
* Hook Event: SessionStart (conceptual - for documentation)
*
* Usage:
* This hook is invoked by AIWG flow commands to suggest session names.
* It can also be used manually:
*
* node aiwg-session.js suggest <workflow-name>
* node aiwg-session.js record <session-name>
* node aiwg-session.js list
*/
const fs = require('fs');
const path = require('path');
// Configuration
const SESSIONS_FILE = process.env.AIWG_SESSIONS_FILE || '.aiwg/sessions.json';
// Generate session name
function generateSessionName(workflowName, context = {}) {
const date = new Date().toISOString().split('T')[0];
const time = new Date().toISOString().split('T')[1].slice(0, 5).replace(':', '');
// Extract iteration if present
const iteration = context.iteration ? `-iter${context.iteration}` : '';
// Extract phase if present
const phase = context.phase ? `-${context.phase}` : '';
// Clean workflow name
const cleanWorkflow = workflowName
.replace(/^flow-/, '')
.replace(/-/g, '-')
.slice(0, 30);
return `aiwg-${cleanWorkflow}${phase}${iteration}-${date}-${time}`;
}
// Load sessions registry
function loadSessions() {
if (fs.existsSync(SESSIONS_FILE)) {
try {
return JSON.parse(fs.readFileSync(SESSIONS_FILE, 'utf-8'));
} catch {
return { sessions: [] };
}
}
return { sessions: [] };
}
// Save sessions registry
function saveSessions(data) {
const dir = path.dirname(SESSIONS_FILE);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(SESSIONS_FILE, JSON.stringify(data, null, 2));
}
// Record a session
function recordSession(name, metadata = {}) {
const data = loadSessions();
data.sessions.push({
name,
created: new Date().toISOString(),
workflow: metadata.workflow || 'unknown',
phase: metadata.phase || null,
iteration: metadata.iteration || null,
status: 'active'
});
// Keep last 50 sessions
if (data.sessions.length > 50) {
data.sessions = data.sessions.slice(-50);
}
saveSessions(data);
return name;
}
// List sessions
function listSessions(filter = {}) {
const data = loadSessions();
let sessions = data.sessions;
if (filter.workflow) {
sessions = sessions.filter(s => s.workflow.includes(filter.workflow));
}
if (filter.status) {
sessions = sessions.filter(s => s.status === filter.status);
}
return sessions.slice(-10).reverse(); // Last 10, newest first
}
// Mark session complete
function completeSession(name) {
const data = loadSessions();
const session = data.sessions.find(s => s.name === name);
if (session) {
session.status = 'complete';
session.completed = new Date().toISOString();
saveSessions(data);
}
return session;
}
// Format session list for output
function formatSessionList(sessions) {
if (sessions.length === 0) {
return 'No sessions found.\n';
}
let output = 'Recent AIWG Sessions:\n\n';
output += '| Name | Workflow | Status | Created |\n';
output += '|------|----------|--------|--------|\n';
for (const s of sessions) {
const date = s.created.split('T')[0];
output += `| ${s.name} | ${s.workflow} | ${s.status} | ${date} |\n`;
}
output += '\nTo resume: claude --resume "<session-name>"\n';
return output;
}
// Main CLI
async function main() {
const command = process.argv[2];
const arg = process.argv[3];
switch (command) {
case 'suggest': {
// Generate suggested session name
const workflow = arg || 'unknown';
const context = {};
// Parse additional context from args
for (let i = 4; i < process.argv.length; i += 2) {
const key = process.argv[i]?.replace('--', '');
const value = process.argv[i + 1];
if (key && value) context[key] = value;
}
const name = generateSessionName(workflow, context);
console.log(name);
break;
}
case 'record': {
// Record a session
const name = arg;
if (!name) {
console.error('Usage: aiwg-session.js record <session-name> [--workflow <name>]');
process.exit(1);
}
const metadata = {};
for (let i = 4; i < process.argv.length; i += 2) {
const key = process.argv[i]?.replace('--', '');
const value = process.argv[i + 1];
if (key && value) metadata[key] = value;
}
recordSession(name, metadata);
console.log(`Recorded session: ${name}`);
break;
}
case 'complete': {
// Mark session complete
const name = arg;
if (!name) {
console.error('Usage: aiwg-session.js complete <session-name>');
process.exit(1);
}
const session = completeSession(name);
if (session) {
console.log(`Completed session: ${name}`);
} else {
console.error(`Session not found: ${name}`);
process.exit(1);
}
break;
}
case 'list': {
// List sessions
const filter = {};
for (let i = 3; i < process.argv.length; i += 2) {
const key = process.argv[i]?.replace('--', '');
const value = process.argv[i + 1];
if (key && value) filter[key] = value;
}
const sessions = listSessions(filter);
console.log(formatSessionList(sessions));
break;
}
default:
console.log(`
AIWG Session Manager
Usage:
aiwg-session.js suggest <workflow> [--phase <phase>] [--iteration <n>]
aiwg-session.js record <name> [--workflow <name>]
aiwg-session.js complete <name>
aiwg-session.js list [--workflow <filter>] [--status <active|complete>]
Examples:
aiwg-session.js suggest inception-to-elaboration
# Output: aiwg-inception-to-elaboration-2025-01-15-1030
aiwg-session.js record aiwg-security-review-2025-01-15 --workflow security-review
aiwg-session.js list
`);
}
}
main().catch(err => {
console.error('Error:', err.message);
process.exit(1);
});