@relipa/ai-flow-kit 0.0.5 → 0.0.6-beta.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/README.md +81 -69
- package/bin/aiflow.js +46 -2
- package/custom/rules/java/spring-boot-examples.md +329 -0
- package/custom/skills/read-study-requirement/SKILL.md +54 -0
- package/custom/skills/review-plan/SKILL.md +21 -0
- package/custom/templates/shared/gate-workflow.md +88 -88
- package/custom/templates/spring-boot.md +224 -523
- package/docs/common/AIFLOW.md +501 -462
- package/docs/common/CHANGELOG.md +162 -132
- package/docs/common/QUICK_START.md +44 -12
- package/docs/common/cli-reference.md +115 -6
- package/docs/common/getting-started.md +3 -0
- package/docs/project/ARCHITECTURE.md +28 -28
- package/package.json +6 -1
- package/scripts/doctor.js +89 -48
- package/scripts/guide.js +28 -5
- package/scripts/hooks/session-start.js +144 -45
- package/scripts/init.js +109 -50
- package/scripts/prompt.js +431 -431
- package/scripts/task.js +384 -0
- package/scripts/telemetry/cli.js +243 -243
- package/scripts/telemetry/config.js +91 -91
- package/scripts/telemetry/crypto.js +20 -20
- package/scripts/telemetry/flush.js +162 -162
- package/scripts/telemetry/record.js +138 -138
- package/scripts/use.js +94 -2
package/scripts/use.js
CHANGED
|
@@ -181,6 +181,7 @@ async function loadFromBacklog(issueKey, options = {}) {
|
|
|
181
181
|
|
|
182
182
|
const comments = filterComments(rawComments, options);
|
|
183
183
|
const context = buildContextFromBacklog(issue, comments, issueKey, domain);
|
|
184
|
+
context.mode = options.full ? 'full' : 'fast';
|
|
184
185
|
await saveContext(context, options.save);
|
|
185
186
|
printContextSummary(context);
|
|
186
187
|
await suggestNextStep();
|
|
@@ -338,6 +339,7 @@ async function loadFromJira(issueKey, options = {}) {
|
|
|
338
339
|
try {
|
|
339
340
|
const issue = await fetchJiraIssue(domain, email, apiToken, issueKey);
|
|
340
341
|
const context = buildContextFromJira(issue, issueKey, domain);
|
|
342
|
+
context.mode = options.full ? 'full' : 'fast';
|
|
341
343
|
await saveContext(context, options.save);
|
|
342
344
|
printContextSummary(context);
|
|
343
345
|
await suggestNextStep();
|
|
@@ -465,6 +467,7 @@ async function manualContext(prefillId = '') {
|
|
|
465
467
|
title,
|
|
466
468
|
description,
|
|
467
469
|
status: existing.status || 'In Progress',
|
|
470
|
+
mode: existing.mode || 'auto',
|
|
468
471
|
acceptanceCriteria: existing.acceptanceCriteria || [],
|
|
469
472
|
context: existing.context || { files: [], relatedTickets: [] },
|
|
470
473
|
metadata: {
|
|
@@ -489,12 +492,62 @@ async function loadFromFile(filePath, options = {}) {
|
|
|
489
492
|
console.log(chalk.red(`File not found: ${filePath}`));
|
|
490
493
|
return;
|
|
491
494
|
}
|
|
492
|
-
|
|
495
|
+
|
|
496
|
+
const raw = await fs.readFile(filePath, 'utf-8');
|
|
497
|
+
let context;
|
|
498
|
+
|
|
499
|
+
// Try JSON first; fall back to plain-text auto-detection
|
|
500
|
+
try {
|
|
501
|
+
context = JSON.parse(raw);
|
|
502
|
+
} catch (_) {
|
|
503
|
+
console.log(chalk.gray(' File is not JSON — auto-detecting task info from content...'));
|
|
504
|
+
context = buildContextFromPlainText(raw);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
context.mode = options.full ? 'full' : 'fast';
|
|
493
508
|
await saveContext(context, options.save);
|
|
494
509
|
printContextSummary(context);
|
|
495
510
|
await suggestNextStep();
|
|
496
511
|
}
|
|
497
512
|
|
|
513
|
+
/**
|
|
514
|
+
* Build a minimal context object from arbitrary plain-text file content.
|
|
515
|
+
* Tries to detect ticket ID (e.g. PROJ-33, APP-123) and a title from the first non-blank line.
|
|
516
|
+
*/
|
|
517
|
+
function buildContextFromPlainText(text) {
|
|
518
|
+
// Detect ticket ID: first PROJ-123 style token anywhere in the text
|
|
519
|
+
const idMatch = text.match(/\b([A-Z][A-Z0-9_]+-\d+)\b/);
|
|
520
|
+
const taskId = idMatch ? idMatch[1] : `TASK-${Date.now()}`;
|
|
521
|
+
|
|
522
|
+
// Title: first non-blank, non-id line (or first line of text)
|
|
523
|
+
const lines = text.split(/\r?\n/).map(l => l.trim()).filter(Boolean);
|
|
524
|
+
const titleLine = lines.find(l => l.length > 3) || taskId;
|
|
525
|
+
const title = titleLine.substring(0, 120);
|
|
526
|
+
|
|
527
|
+
// Task type detection from text
|
|
528
|
+
const taskType = detectTaskTypeFromString(text);
|
|
529
|
+
|
|
530
|
+
return {
|
|
531
|
+
taskId,
|
|
532
|
+
taskType,
|
|
533
|
+
title,
|
|
534
|
+
description: text.substring(0, 3000),
|
|
535
|
+
status: 'In Progress',
|
|
536
|
+
assignee: 'Unassigned',
|
|
537
|
+
acceptanceCriteria: extractCriteria(text),
|
|
538
|
+
context: {
|
|
539
|
+
files: extractFiles(text),
|
|
540
|
+
relatedTickets: extractRelatedTickets(text),
|
|
541
|
+
},
|
|
542
|
+
metadata: {
|
|
543
|
+
created: new Date().toISOString(),
|
|
544
|
+
updated: new Date().toISOString(),
|
|
545
|
+
loadedFrom: 'file',
|
|
546
|
+
adapter: 'file',
|
|
547
|
+
},
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
498
551
|
// ──────────────────────────────────────────────────────────────
|
|
499
552
|
// Credentials loader — global (~/.aiflow/credentials.json) with project fallback
|
|
500
553
|
// ──────────────────────────────────────────────────────────────
|
|
@@ -521,8 +574,39 @@ async function saveContext(context, saveName) {
|
|
|
521
574
|
await fs.ensureDir(CONTEXT_DIR);
|
|
522
575
|
await fs.ensureDir(path.join(CONTEXT_DIR, 'history'));
|
|
523
576
|
|
|
577
|
+
// Auto-pause any currently active task that differs from this one
|
|
578
|
+
const currentFile = path.join(CONTEXT_DIR, 'current.json');
|
|
579
|
+
if (context.taskId && (await fs.pathExists(currentFile))) {
|
|
580
|
+
const prev = await fs.readJson(currentFile).catch(() => null);
|
|
581
|
+
if (prev && prev.taskId && prev.taskId !== context.taskId) {
|
|
582
|
+
try {
|
|
583
|
+
const { createOrActivateTaskState } = require('./task');
|
|
584
|
+
// Save previous task state as pending before switching
|
|
585
|
+
const prevTaskDir = path.join(AIFLOW_DIR, 'tasks', prev.taskId);
|
|
586
|
+
const prevStatePath = path.join(prevTaskDir, 'task-state.json');
|
|
587
|
+
await fs.ensureDir(prevTaskDir);
|
|
588
|
+
await fs.writeJson(path.join(prevTaskDir, 'context.json'), prev, { spaces: 2 });
|
|
589
|
+
const prevState = (await fs.pathExists(prevStatePath)) ? await fs.readJson(prevStatePath).catch(() => ({})) : {};
|
|
590
|
+
const now = new Date().toISOString();
|
|
591
|
+
await fs.writeJson(prevStatePath, {
|
|
592
|
+
...prevState,
|
|
593
|
+
taskId: prev.taskId,
|
|
594
|
+
title: prev.title || '',
|
|
595
|
+
status: 'pending',
|
|
596
|
+
updatedAt: now,
|
|
597
|
+
pausedAt: now,
|
|
598
|
+
currentGate: prevState.currentGate || 1,
|
|
599
|
+
gateApprovals: prevState.gateApprovals || {},
|
|
600
|
+
notes: prevState.notes || '',
|
|
601
|
+
createdAt: prevState.createdAt || now,
|
|
602
|
+
}, { spaces: 2 });
|
|
603
|
+
console.log(chalk.gray(` Auto-paused previous task: ${prev.taskId}`));
|
|
604
|
+
} catch (_) { /* task module not available */ }
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
524
608
|
// Save as current
|
|
525
|
-
await fs.writeJson(
|
|
609
|
+
await fs.writeJson(currentFile, context, { spaces: 2 });
|
|
526
610
|
|
|
527
611
|
// Save to history
|
|
528
612
|
const histFile = path.join(CONTEXT_DIR, 'history', `${context.taskId || 'manual'}.json`);
|
|
@@ -535,6 +619,14 @@ async function saveContext(context, saveName) {
|
|
|
535
619
|
console.log(chalk.gray(` Context also saved as: ${saveName}`));
|
|
536
620
|
}
|
|
537
621
|
|
|
622
|
+
// Create / activate task-state for the new task
|
|
623
|
+
if (context.taskId) {
|
|
624
|
+
try {
|
|
625
|
+
const { createOrActivateTaskState } = require('./task');
|
|
626
|
+
await createOrActivateTaskState(context);
|
|
627
|
+
} catch (_) { /* task module not available */ }
|
|
628
|
+
}
|
|
629
|
+
|
|
538
630
|
// Update state
|
|
539
631
|
if (await fs.pathExists(STATE_FILE)) {
|
|
540
632
|
const state = await fs.readJson(STATE_FILE);
|