@trim21/personal-pi-extensions 0.1.542 → 0.1.544
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/package.json +1 -1
- package/src/gh-readonly.ts +38 -14
package/package.json
CHANGED
package/src/gh-readonly.ts
CHANGED
|
@@ -425,6 +425,11 @@ export function stepsDetail(
|
|
|
425
425
|
// 缓存检查避免重复网络请求。闭包状态不与其他扩展共享,key 无需全局前缀。
|
|
426
426
|
const seq = createSeqState();
|
|
427
427
|
|
|
428
|
+
/** Absolute path of the raw job log cache file written by `getJobLog`. */
|
|
429
|
+
export function jobLogPath(runId: string, jobId: number): string {
|
|
430
|
+
return join(homedir(), ".cache", "pi", "ci-logs", runId, `${jobId}.log`);
|
|
431
|
+
}
|
|
432
|
+
|
|
428
433
|
async function getJobLog(
|
|
429
434
|
runId: string,
|
|
430
435
|
jobId: number,
|
|
@@ -433,8 +438,8 @@ async function getJobLog(
|
|
|
433
438
|
cwd: string | undefined,
|
|
434
439
|
input?: unknown,
|
|
435
440
|
): Promise<string> {
|
|
436
|
-
const
|
|
437
|
-
const
|
|
441
|
+
const cacheFile = jobLogPath(runId, jobId);
|
|
442
|
+
const cacheDir = dirname(cacheFile);
|
|
438
443
|
|
|
439
444
|
// 同一 runId:jobId 的请求串行执行:后一个进入时缓存已写入,直接命中缓存,
|
|
440
445
|
// 不会重复发网络请求;串行也保证不会有两个并发写同一 cache 文件。
|
|
@@ -682,6 +687,15 @@ export function stripAnsi(text: string): string {
|
|
|
682
687
|
return text.replace(/^\uFEFF/, "").replaceAll(ANSI_RE, "");
|
|
683
688
|
}
|
|
684
689
|
|
|
690
|
+
/**
|
|
691
|
+
* Appended to `read-github-ci-logs` content so the raw log file path reaches
|
|
692
|
+
* the model: tool `details` is not part of the LLM context, so the path has to
|
|
693
|
+
* live in the returned text.
|
|
694
|
+
*/
|
|
695
|
+
function rawLogNotice(path: string): string {
|
|
696
|
+
return `[Raw job log (whole job): ${path}]`;
|
|
697
|
+
}
|
|
698
|
+
|
|
685
699
|
export interface StepLogParams {
|
|
686
700
|
runId: string;
|
|
687
701
|
job?: string;
|
|
@@ -772,6 +786,7 @@ export async function renderStepLog(
|
|
|
772
786
|
});
|
|
773
787
|
|
|
774
788
|
const rawLog = await fetchJobLog(targetJob.id);
|
|
789
|
+
const rawLogFile = jobLogPath(params.runId, targetJob.id);
|
|
775
790
|
|
|
776
791
|
const stepLog = extractStepFromLog(rawLog, stepNum, targetJob.steps);
|
|
777
792
|
if (stepLog === null) {
|
|
@@ -779,10 +794,10 @@ export async function renderStepLog(
|
|
|
779
794
|
content: [
|
|
780
795
|
{
|
|
781
796
|
type: "text",
|
|
782
|
-
text: `Could not extract step ${stepNum} from job "${targetJob.name}" logs. The log may be malformed or empty
|
|
797
|
+
text: `Could not extract step ${stepNum} from job "${targetJob.name}" logs. The log may be malformed or empty — read the raw file instead.\n\n${rawLogNotice(rawLogFile)}`,
|
|
783
798
|
},
|
|
784
799
|
],
|
|
785
|
-
details: {},
|
|
800
|
+
details: { rawLogFile },
|
|
786
801
|
};
|
|
787
802
|
}
|
|
788
803
|
|
|
@@ -792,11 +807,12 @@ export async function renderStepLog(
|
|
|
792
807
|
if (full) {
|
|
793
808
|
const fullLines = clean.split("\n").length;
|
|
794
809
|
return {
|
|
795
|
-
content: [{ type: "text", text: clean }],
|
|
810
|
+
content: [{ type: "text", text: `${clean}\n\n${rawLogNotice(rawLogFile)}` }],
|
|
796
811
|
details: {
|
|
797
812
|
summary: `Step ${stepNum} — ${targetJob.name} / ${found.name}: complete output (${fullLines} lines)`,
|
|
798
813
|
truncated: false,
|
|
799
814
|
full: true,
|
|
815
|
+
rawLogFile,
|
|
800
816
|
job: {
|
|
801
817
|
name: targetJob.name,
|
|
802
818
|
conclusion: targetJob.conclusion,
|
|
@@ -818,10 +834,10 @@ export async function renderStepLog(
|
|
|
818
834
|
content: [
|
|
819
835
|
{
|
|
820
836
|
type: "text",
|
|
821
|
-
text: `Offset ${offset} exceeds step log length (${totalLines} lines)
|
|
837
|
+
text: `Offset ${offset} exceeds step log length (${totalLines} lines).\n\n${rawLogNotice(rawLogFile)}`,
|
|
822
838
|
},
|
|
823
839
|
],
|
|
824
|
-
details: {},
|
|
840
|
+
details: { rawLogFile },
|
|
825
841
|
};
|
|
826
842
|
}
|
|
827
843
|
logToShow = clean
|
|
@@ -837,10 +853,11 @@ export async function renderStepLog(
|
|
|
837
853
|
const shownLines = text.split("\n").length;
|
|
838
854
|
|
|
839
855
|
return {
|
|
840
|
-
content: [{ type: "text", text }],
|
|
856
|
+
content: [{ type: "text", text: `${text}\n\n${rawLogNotice(rawLogFile)}` }],
|
|
841
857
|
details: {
|
|
842
858
|
summary: `Step ${stepNum} — ${targetJob.name} / ${found.name}: ${shownLines} of ${totalLines} lines${tr ? " (truncated)" : ""}`,
|
|
843
859
|
truncated: tr,
|
|
860
|
+
rawLogFile,
|
|
844
861
|
job: {
|
|
845
862
|
name: targetJob.name,
|
|
846
863
|
conclusion: targetJob.conclusion,
|
|
@@ -869,15 +886,18 @@ export interface JobLogsStep {
|
|
|
869
886
|
|
|
870
887
|
export interface JobLogsOutput {
|
|
871
888
|
name: string;
|
|
889
|
+
/** Absolute path of this job's raw log on disk, set when its log was fetched. */
|
|
890
|
+
log_file?: string;
|
|
872
891
|
steps: JobLogsStep[];
|
|
873
892
|
}
|
|
874
893
|
|
|
875
894
|
/**
|
|
876
895
|
* Render the result of `read-github-ci-logs` without a `step`: a JSON array of
|
|
877
|
-
* jobs `[{ name, steps: [{ name, output? }] }]`. Every step is listed
|
|
878
|
-
* only failed steps carry an `output` (their log as plain text).
|
|
879
|
-
*
|
|
880
|
-
*
|
|
896
|
+
* jobs `[{ name, log_file?, steps: [{ name, output? }] }]`. Every step is listed
|
|
897
|
+
* by name; only failed steps carry an `output` (their log as plain text).
|
|
898
|
+
* `log_file` is the raw on-disk log path for jobs whose log was fetched. `job`
|
|
899
|
+
* is an optional filter; `offset`/`limit` control the size of each `output`
|
|
900
|
+
* text. Pure — no network, no `gh`.
|
|
881
901
|
*/
|
|
882
902
|
export async function renderJobLogs(
|
|
883
903
|
params: JobLogsParams,
|
|
@@ -961,7 +981,11 @@ export async function renderJobLogs(
|
|
|
961
981
|
}
|
|
962
982
|
}
|
|
963
983
|
|
|
964
|
-
output.push({
|
|
984
|
+
output.push({
|
|
985
|
+
name: j.name,
|
|
986
|
+
...(rawLog !== null && { log_file: jobLogPath(params.runId, j.id) }),
|
|
987
|
+
steps,
|
|
988
|
+
});
|
|
965
989
|
}
|
|
966
990
|
|
|
967
991
|
const totalJobs = output.length;
|
|
@@ -1856,7 +1880,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
|
|
|
1856
1880
|
name: "read-github-ci-logs",
|
|
1857
1881
|
label: "GitHub CI Logs",
|
|
1858
1882
|
description:
|
|
1859
|
-
"Get CI logs from a GitHub Actions workflow run. Without step: returns a JSON array of jobs [{name, steps:[{name, output?}]}] where every step is listed by name and failed steps carry their log as plain text in `output`. With step (requires job): returns that step's complete log as plain text. offset/limit control the size of every expanded output. Use run_id from list-github-workflow-runs. Note: queued jobs have no logs yet; use watch-github-run to wait for completion. Set full=true for complete untruncated outputs (every step when step is omitted; caution: very large outputs consume a lot of LLM context). Set output_file=/path to write the complete log to
|
|
1883
|
+
"Get CI logs from a GitHub Actions workflow run. Without step: returns a JSON array of jobs [{name, log_file?, steps:[{name, output?}]}] where every step is listed by name and failed steps carry their log as plain text in `output`. With step (requires job): returns that step's complete log as plain text. Every fetched job log is also saved raw (timestamps and ANSI kept) to a local file whose path is reported — `log_file` on the job, or a trailing `[Raw job log (whole job): <path>]` line with step — so read/grep that file for the complete, untruncated log. offset/limit control the size of every expanded output. Use run_id from list-github-workflow-runs. Note: queued jobs have no logs yet; use watch-github-run to wait for completion. Set full=true for complete untruncated outputs (every step when step is omitted; caution: very large outputs consume a lot of LLM context). Set output_file=/path to write the complete cleaned log to this file instead of returning it (requires job when the run has multiple jobs); the tool returns the file path to read.",
|
|
1860
1884
|
promptSnippet: "Read GitHub CI logs",
|
|
1861
1885
|
parameters: Type.Object({
|
|
1862
1886
|
run_id: Type.Union([Type.Number(), Type.String()], { description: "Workflow run ID" }),
|