@relipa/ai-flow-kit 0.0.5-beta.1 → 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/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
- const context = await fs.readJson(filePath);
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(path.join(CONTEXT_DIR, 'current.json'), context, { spaces: 2 });
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);