@exaudeus/workrail 3.80.0 → 3.81.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.
@@ -52,6 +52,7 @@ const index_js_1 = require("./context-assembly/index.js");
52
52
  const infra_js_1 = require("./context-assembly/infra.js");
53
53
  const index_js_2 = require("./cli/commands/index.js");
54
54
  const stats_summary_js_1 = require("./daemon/stats-summary.js");
55
+ const worktrain_diagnose_js_1 = require("./cli/commands/worktrain-diagnose.js");
55
56
  const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
56
57
  const program = new commander_1.Command();
57
58
  program
@@ -744,6 +745,31 @@ program
744
745
  }
745
746
  }
746
747
  });
748
+ program
749
+ .command('diagnose <sessionId>')
750
+ .description('Print a failure card for a daemon session. Searches the last 7 days of daemon event logs. ' +
751
+ 'Works without the daemon running. Accepts sessionId (UUID prefix) or workrailSessionId (sess_xxx).')
752
+ .option('--json', 'Output machine-readable JSON (full untruncated fields)')
753
+ .option('--ascii', 'Use ASCII-only output (no Unicode glyphs)')
754
+ .action((sessionId, options) => {
755
+ const eventsDir = path_1.default.join(os_1.default.homedir(), '.workrail', 'events', 'daemon');
756
+ const readFile = (filePath) => {
757
+ try {
758
+ return fs_1.default.readFileSync(filePath, 'utf8');
759
+ }
760
+ catch {
761
+ return null;
762
+ }
763
+ };
764
+ const result = (0, worktrain_diagnose_js_1.parseDaemonEvents)(sessionId, eventsDir, 7, readFile);
765
+ if (options.json) {
766
+ process.stdout.write((0, worktrain_diagnose_js_1.formatDiagnosticJson)(result) + '\n');
767
+ }
768
+ else {
769
+ const card = (0, worktrain_diagnose_js_1.formatDiagnosticCard)(result, { ascii: options.ascii ?? false });
770
+ process.stdout.write(card + '\n');
771
+ }
772
+ });
747
773
  program
748
774
  .command('health <sessionId>')
749
775
  .description('Print a health summary for a daemon session. Accepts sessionId (UUID prefix) or workrailSessionId (sess_xxx).')
@@ -760,7 +786,34 @@ program
760
786
  raw = fs_1.default.readFileSync(filePath, 'utf8');
761
787
  }
762
788
  catch {
763
- process.stdout.write(`No events today. Is the daemon running? (Expected: ${filePath})\n`);
789
+ raw = '';
790
+ }
791
+ const sessionInTodayLog = raw.split('\n').some((line) => {
792
+ if (!line.trim())
793
+ return false;
794
+ try {
795
+ const obj = JSON.parse(line);
796
+ const sid = typeof obj['sessionId'] === 'string' ? obj['sessionId'] : '';
797
+ const wrid = typeof obj['workrailSessionId'] === 'string' ? obj['workrailSessionId'] : '';
798
+ return sid.startsWith(sessionId) || sid === sessionId ||
799
+ wrid.startsWith(sessionId) || wrid === sessionId;
800
+ }
801
+ catch {
802
+ return false;
803
+ }
804
+ });
805
+ if (!sessionInTodayLog) {
806
+ const readFile = (fp) => {
807
+ try {
808
+ return fs_1.default.readFileSync(fp, 'utf8');
809
+ }
810
+ catch {
811
+ return null;
812
+ }
813
+ };
814
+ const result = (0, worktrain_diagnose_js_1.parseDaemonEvents)(sessionId, eventsDir, 7, readFile);
815
+ const card = (0, worktrain_diagnose_js_1.formatDiagnosticCard)(result);
816
+ process.stdout.write(card + '\n');
764
817
  return;
765
818
  }
766
819
  runHealthSummary(sessionId, raw);
@@ -782,15 +835,40 @@ program
782
835
  const eventsDir = path_1.default.join(os_1.default.homedir(), '.workrail', 'events', 'daemon');
783
836
  const date = new Date().toISOString().slice(0, 10);
784
837
  const filePath = path_1.default.join(eventsDir, `${date}.jsonl`);
785
- let raw;
838
+ let raw = '';
786
839
  try {
787
840
  raw = fs_1.default.readFileSync(filePath, 'utf8');
788
841
  }
789
842
  catch {
790
- process.stdout.write(`No events today. Is the daemon running? (Expected: ${filePath})\n`);
791
- return;
792
843
  }
793
844
  process.stderr.write(`\nNote: This is the old \`worktrain status <id>\` output. Use \`worktrain health <id>\` instead.\n\n`);
845
+ const sessionInTodayLog = raw.split('\n').some((line) => {
846
+ if (!line.trim())
847
+ return false;
848
+ try {
849
+ const obj = JSON.parse(line);
850
+ const sid = typeof obj['sessionId'] === 'string' ? obj['sessionId'] : '';
851
+ const wrid = typeof obj['workrailSessionId'] === 'string' ? obj['workrailSessionId'] : '';
852
+ return sid.startsWith(sessionId) || sid === sessionId ||
853
+ wrid.startsWith(sessionId) || wrid === sessionId;
854
+ }
855
+ catch {
856
+ return false;
857
+ }
858
+ });
859
+ if (!sessionInTodayLog) {
860
+ const readFile = (fp) => {
861
+ try {
862
+ return fs_1.default.readFileSync(fp, 'utf8');
863
+ }
864
+ catch {
865
+ return null;
866
+ }
867
+ };
868
+ const result = (0, worktrain_diagnose_js_1.parseDaemonEvents)(sessionId, eventsDir, 7, readFile);
869
+ process.stdout.write((0, worktrain_diagnose_js_1.formatDiagnosticCard)(result) + '\n');
870
+ return;
871
+ }
794
872
  runHealthSummary(sessionId, raw);
795
873
  return;
796
874
  }