@exaudeus/workrail 3.80.0 → 3.82.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/dist/cli/commands/worktrain-diagnose.d.ts +132 -0
- package/dist/cli/commands/worktrain-diagnose.js +822 -0
- package/dist/cli-worktrain.js +97 -4
- package/dist/console-ui/assets/{index-2NrQPYdF.js → index-DE4aB2eN.js} +1 -1
- package/dist/console-ui/index.html +1 -1
- package/dist/manifest.json +13 -5
- package/docs/ideas/backlog.md +32 -1
- package/package.json +1 -1
package/dist/cli-worktrain.js
CHANGED
|
@@ -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,46 @@ program
|
|
|
744
745
|
}
|
|
745
746
|
}
|
|
746
747
|
});
|
|
748
|
+
program
|
|
749
|
+
.command('diagnose [sessionId]')
|
|
750
|
+
.description('Session diagnostics. No args: fleet summary with step bottleneck analysis and token burn. ' +
|
|
751
|
+
'Pass a sessionId for a per-session failure card with evidence and suggested fix. ' +
|
|
752
|
+
'Searches the last 7 days of daemon event logs. Works without the daemon running.')
|
|
753
|
+
.option('--workflow <id>', 'Filter fleet view by workflow ID (e.g. wr.discovery)')
|
|
754
|
+
.option('--json', 'Output machine-readable JSON (per-session only)')
|
|
755
|
+
.option('--ascii', 'Use ASCII-only output (no Unicode glyphs)')
|
|
756
|
+
.action((sessionId, options) => {
|
|
757
|
+
const eventsDir = path_1.default.join(os_1.default.homedir(), '.workrail', 'events', 'daemon');
|
|
758
|
+
const readFile = (filePath) => {
|
|
759
|
+
try {
|
|
760
|
+
return fs_1.default.readFileSync(filePath, 'utf8');
|
|
761
|
+
}
|
|
762
|
+
catch {
|
|
763
|
+
return null;
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
if (sessionId !== undefined) {
|
|
767
|
+
const result = (0, worktrain_diagnose_js_1.parseDaemonEvents)(sessionId, eventsDir, 7, readFile);
|
|
768
|
+
if (options.json) {
|
|
769
|
+
process.stdout.write((0, worktrain_diagnose_js_1.formatDiagnosticJson)(result) + '\n');
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
process.stdout.write((0, worktrain_diagnose_js_1.formatDiagnosticCard)(result, { ascii: options.ascii ?? false }) + '\n');
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
else {
|
|
776
|
+
const readDir = (dir) => {
|
|
777
|
+
try {
|
|
778
|
+
return fs_1.default.readdirSync(dir);
|
|
779
|
+
}
|
|
780
|
+
catch {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
const analysis = (0, worktrain_diagnose_js_1.analyzeFleet)(readDir, readFile, eventsDir, options.workflow);
|
|
785
|
+
process.stdout.write((0, worktrain_diagnose_js_1.formatFleetSummary)(analysis, { ascii: options.ascii ?? false }) + '\n');
|
|
786
|
+
}
|
|
787
|
+
});
|
|
747
788
|
program
|
|
748
789
|
.command('health <sessionId>')
|
|
749
790
|
.description('Print a health summary for a daemon session. Accepts sessionId (UUID prefix) or workrailSessionId (sess_xxx).')
|
|
@@ -760,7 +801,34 @@ program
|
|
|
760
801
|
raw = fs_1.default.readFileSync(filePath, 'utf8');
|
|
761
802
|
}
|
|
762
803
|
catch {
|
|
763
|
-
|
|
804
|
+
raw = '';
|
|
805
|
+
}
|
|
806
|
+
const sessionInTodayLog = raw.split('\n').some((line) => {
|
|
807
|
+
if (!line.trim())
|
|
808
|
+
return false;
|
|
809
|
+
try {
|
|
810
|
+
const obj = JSON.parse(line);
|
|
811
|
+
const sid = typeof obj['sessionId'] === 'string' ? obj['sessionId'] : '';
|
|
812
|
+
const wrid = typeof obj['workrailSessionId'] === 'string' ? obj['workrailSessionId'] : '';
|
|
813
|
+
return sid.startsWith(sessionId) || sid === sessionId ||
|
|
814
|
+
wrid.startsWith(sessionId) || wrid === sessionId;
|
|
815
|
+
}
|
|
816
|
+
catch {
|
|
817
|
+
return false;
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
if (!sessionInTodayLog) {
|
|
821
|
+
const readFile = (fp) => {
|
|
822
|
+
try {
|
|
823
|
+
return fs_1.default.readFileSync(fp, 'utf8');
|
|
824
|
+
}
|
|
825
|
+
catch {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
const result = (0, worktrain_diagnose_js_1.parseDaemonEvents)(sessionId, eventsDir, 7, readFile);
|
|
830
|
+
const card = (0, worktrain_diagnose_js_1.formatDiagnosticCard)(result);
|
|
831
|
+
process.stdout.write(card + '\n');
|
|
764
832
|
return;
|
|
765
833
|
}
|
|
766
834
|
runHealthSummary(sessionId, raw);
|
|
@@ -782,15 +850,40 @@ program
|
|
|
782
850
|
const eventsDir = path_1.default.join(os_1.default.homedir(), '.workrail', 'events', 'daemon');
|
|
783
851
|
const date = new Date().toISOString().slice(0, 10);
|
|
784
852
|
const filePath = path_1.default.join(eventsDir, `${date}.jsonl`);
|
|
785
|
-
let raw;
|
|
853
|
+
let raw = '';
|
|
786
854
|
try {
|
|
787
855
|
raw = fs_1.default.readFileSync(filePath, 'utf8');
|
|
788
856
|
}
|
|
789
857
|
catch {
|
|
790
|
-
process.stdout.write(`No events today. Is the daemon running? (Expected: ${filePath})\n`);
|
|
791
|
-
return;
|
|
792
858
|
}
|
|
793
859
|
process.stderr.write(`\nNote: This is the old \`worktrain status <id>\` output. Use \`worktrain health <id>\` instead.\n\n`);
|
|
860
|
+
const sessionInTodayLog = raw.split('\n').some((line) => {
|
|
861
|
+
if (!line.trim())
|
|
862
|
+
return false;
|
|
863
|
+
try {
|
|
864
|
+
const obj = JSON.parse(line);
|
|
865
|
+
const sid = typeof obj['sessionId'] === 'string' ? obj['sessionId'] : '';
|
|
866
|
+
const wrid = typeof obj['workrailSessionId'] === 'string' ? obj['workrailSessionId'] : '';
|
|
867
|
+
return sid.startsWith(sessionId) || sid === sessionId ||
|
|
868
|
+
wrid.startsWith(sessionId) || wrid === sessionId;
|
|
869
|
+
}
|
|
870
|
+
catch {
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
if (!sessionInTodayLog) {
|
|
875
|
+
const readFile = (fp) => {
|
|
876
|
+
try {
|
|
877
|
+
return fs_1.default.readFileSync(fp, 'utf8');
|
|
878
|
+
}
|
|
879
|
+
catch {
|
|
880
|
+
return null;
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
const result = (0, worktrain_diagnose_js_1.parseDaemonEvents)(sessionId, eventsDir, 7, readFile);
|
|
884
|
+
process.stdout.write((0, worktrain_diagnose_js_1.formatDiagnosticCard)(result) + '\n');
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
794
887
|
runHealthSummary(sessionId, raw);
|
|
795
888
|
return;
|
|
796
889
|
}
|