@jixoai/gh-runner 0.0.0 → 0.2.1

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.
@@ -0,0 +1,194 @@
1
+ /*
2
+ * 演示模式数据源(仅普通浏览器打开 index.html 时由 index.html 动态加载):
3
+ * 模拟 4 台实例的完整生命周期,按与真实宿主相同的 summary/log 双通道协议驱动渲染,
4
+ * 供走查/截图/自动化验收。
5
+ */
6
+ "use strict";
7
+ (function () {
8
+ const now = Date.now();
9
+ const mk = (id, name, over) => Object.assign({
10
+ id, dir: `/Volumes/bnqkl/Users/kzf/actions-runner${name === "mac-ext-01" ? "" : name.slice(-2)}`,
11
+ name, agentId: 99 + Number(name.slice(-2)) - 1, orgUrl: "https://github.com/jixoai",
12
+ workFolder: "/Volumes/bnqkl/Users/kzf/gh-runner-work", configured: true,
13
+ processState: "stopped", external: false, autoStart: false, pid: null,
14
+ currentJob: null, lastResult: null, lastError: null, log: [], logTotal: 0,
15
+ }, over);
16
+
17
+ const instances = [
18
+ mk("actions-runner", "mac-ext-01", {
19
+ processState: "running", external: true, pid: 75037, autoStart: true,
20
+ currentJob: { job: "deploy", startedAt: new Date(now - 95_000).toISOString() },
21
+ lastResult: { job: "build-win", outcome: "Succeeded", at: new Date(now - 12 * 60_000).toISOString(), durationMs: 118_000 },
22
+ log: [
23
+ "2026-10-24 11:39:46Z: Running job: deploy",
24
+ "2026-10-24 11:41:36Z: Job deploy completed with result: Succeeded",
25
+ "2026-10-24 11:57:17Z: Running job: lint-test-scan",
26
+ "2026-10-24 11:58:07Z: Job lint-test-scan completed with result: Failed",
27
+ "2026-10-24 12:10:36Z: Running job: lint-test-scan",
28
+ "2026-10-24 12:13:04Z: Job lint-test-scan completed with result: Succeeded",
29
+ "2026-10-24 12:18:02Z: Running job: deploy",
30
+ ],
31
+ }),
32
+ mk("actions-runner-2", "mac-ext-02", {
33
+ processState: "running", external: true, pid: 49420,
34
+ lastResult: { job: "test(typecheck+vitest+build)", outcome: "Succeeded", at: new Date(now - 40 * 60_000).toISOString(), durationMs: 32_000 },
35
+ log: ["2026-10-24 11:36:40Z: Listening for Jobs"],
36
+ }),
37
+ mk("actions-runner-03", "mac-ext-03", {
38
+ processState: "running", external: true, pid: 50402,
39
+ lastResult: { job: "核心门禁(cli / contracts / icons / hermes)", outcome: "Failed", at: new Date(now - 3 * 60_000).toISOString(), durationMs: 26_000 },
40
+ log: [
41
+ "2026-10-24 12:15:11Z: Running job: 核心门禁(cli / contracts / icons / hermes)",
42
+ "2026-10-24 12:15:37Z: Job 核心门禁(cli / contracts / icons / hermes) completed with result: Failed",
43
+ "2026-10-24 12:15:40Z: Listening for Jobs",
44
+ ],
45
+ }),
46
+ mk("actions-runner-04", "mac-ext-04", { processState: "stopped" }),
47
+ ];
48
+ for (const inst of instances) inst.logTotal = inst.log.length;
49
+ const logSent = new Map();
50
+
51
+ let seq = 0;
52
+ const packages = [
53
+ { path: "/Volumes/bnqkl/Users/kzf/actions-runner/actions-runner-osx-arm64-2.338.1.tar.gz", name: "actions-runner-osx-arm64-2.338.1.tar.gz", sizeBytes: 214 * 1024 * 1024, mtimeMs: now - 3600_000, compatible: true },
54
+ { path: "/Users/kzf/Downloads/actions-runner-win-x64-2.339.0.zip", name: "actions-runner-win-x64-2.339.0.zip", sizeBytes: 198 * 1024 * 1024, mtimeMs: now - 86_400_000, compatible: false },
55
+ ];
56
+ let download = null;
57
+ function sink() {
58
+ seq += 1;
59
+ window.__rfSink({
60
+ kind: "summary",
61
+ seq,
62
+ now: new Date().toISOString(),
63
+ platform: "darwin",
64
+ arch: "arm64",
65
+ task: window.__demo.task,
66
+ instances: instances.map(({ log: _log, ...rest }) => rest),
67
+ packages: JSON.parse(JSON.stringify(packages)),
68
+ download: download ? { ...download } : null,
69
+ });
70
+ for (const inst of instances) {
71
+ const sent = logSent.get(inst.id) ?? 0;
72
+ if (inst.logTotal > sent) {
73
+ seq += 1;
74
+ window.__rfSink({
75
+ kind: "log",
76
+ seq,
77
+ id: inst.id,
78
+ from: sent,
79
+ truncated: false,
80
+ lines: inst.log.slice(sent),
81
+ });
82
+ logSent.set(inst.id, inst.logTotal);
83
+ }
84
+ }
85
+ }
86
+
87
+ function addLog(inst, line) {
88
+ inst.log.push(line);
89
+ inst.logTotal += 1;
90
+ }
91
+
92
+ const demo = (window.__demo = {
93
+ task: { kind: "none", status: "ok", message: null },
94
+ command(cmd) {
95
+ // hello/ack 是页面回声,不能触发 sink——否则 ack→sink→ack 无限递归(栈溢出,日志通道全断)。
96
+ if (cmd.type === "ack" || cmd.type === "hello") return;
97
+ const inst = instances.find((i) => i.id === cmd.id);
98
+ if (cmd.type === "start" && inst) {
99
+ inst.processState = "running";
100
+ addLog(inst, ts() + " Listening for Jobs");
101
+ setTimeout(() => {
102
+ if (inst.processState !== "running") return;
103
+ inst.currentJob = { job: "lint-test-scan", startedAt: new Date().toISOString() };
104
+ addLog(inst, ts() + " Running job: lint-test-scan");
105
+ sink();
106
+ setTimeout(() => {
107
+ if (!inst.currentJob) return;
108
+ const ok = Math.random() > 0.35;
109
+ inst.lastResult = { job: inst.currentJob.job, outcome: ok ? "Succeeded" : "Failed", at: new Date().toISOString(), durationMs: 21_000 };
110
+ addLog(inst, ts() + ` Job ${inst.currentJob.job} completed with result: ${inst.lastResult.outcome}`);
111
+ inst.currentJob = null;
112
+ addLog(inst, ts() + " Listening for Jobs");
113
+ sink();
114
+ }, 8000);
115
+ }, 1200);
116
+ }
117
+ if (cmd.type === "stop" && inst) {
118
+ inst.processState = "stopped";
119
+ inst.currentJob = null;
120
+ inst.pid = null;
121
+ inst.external = false;
122
+ }
123
+ if (cmd.type === "set-auto-start" && inst) inst.autoStart = cmd.value;
124
+ if (cmd.type === "download-latest") {
125
+ if (download && download.status === "running") return;
126
+ download = { status: "running", pct: 0, message: "下载 actions-runner-osx-arm64-2.340.0.tar.gz(演示)" };
127
+ sink();
128
+ let pct = 0;
129
+ const t = setInterval(() => {
130
+ pct = Math.min(100, pct + Math.ceil(Math.random() * 18));
131
+ download = { status: "running", pct, message: "下载 actions-runner-osx-arm64-2.340.0.tar.gz(演示)" };
132
+ if (pct >= 100) {
133
+ clearInterval(t);
134
+ download = { status: "ok", pct: 100, message: "已下载 /Users/kzf/Library/Application Support/gh-runner/packages/actions-runner-osx-arm64-2.340.0.tar.gz(演示)" };
135
+ packages.unshift({ path: download.message.slice(4).replace("(演示)", ""), name: "actions-runner-osx-arm64-2.340.0.tar.gz", sizeBytes: 221 * 1024 * 1024, mtimeMs: Date.now(), compatible: true });
136
+ }
137
+ sink();
138
+ }, 400);
139
+ }
140
+ if (cmd.type === "import-package") {
141
+ // 真实宿主走 ext-dialog 系统对话框;演示直接登记一个假路径
142
+ packages.unshift({ path: "/Users/kzf/Downloads/actions-runner-osx-arm64-2.341.0.tar.gz", name: "actions-runner-osx-arm64-2.341.0.tar.gz", sizeBytes: 223 * 1024 * 1024, mtimeMs: Date.now(), compatible: true });
143
+ }
144
+ if (cmd.type === "register") {
145
+ demo.task = { kind: "register", status: "running", message: "(演示)开始注册…" };
146
+ const lines = ["$ 解包分发包", " x actions-runner/", " x actions-runner/bin/", "$ 移除 quarantine 隔离标记", "$ config.sh 注册", " √ Connected to GitHub", " √ Runner successfully added"];
147
+ let i = 0;
148
+ const t = setInterval(() => {
149
+ if (i < lines.length) {
150
+ demo.task = { kind: "register", status: "running", message: lines[i++] };
151
+ } else {
152
+ clearInterval(t);
153
+ // 与真实语义一致:注册目标必须是新目录 → 生成全新实例,而不是顶掉既有实例。
154
+ const fresh = mk("actions-runner-5", cmd.name || "mac-ext-05", {});
155
+ fresh.dir = cmd.dir || fresh.dir;
156
+ fresh.processState = "stopped";
157
+ instances.push(fresh);
158
+ demo.task = { kind: "register", status: "ok", message: `${fresh.name} 注册成功(演示)` };
159
+ demo.command({ type: "start", id: fresh.id });
160
+ }
161
+ sink();
162
+ }, 700);
163
+ }
164
+ sink();
165
+ },
166
+ });
167
+
168
+ function ts() {
169
+ const d = new Date();
170
+ const p = (n) => String(n).padStart(2, "0");
171
+ return `${d.getUTCFullYear()}-${p(d.getUTCMonth() + 1)}-${p(d.getUTCDate())} ${p(d.getUTCHours())}:${p(d.getUTCMinutes())}:${p(d.getUTCSeconds())}Z`;
172
+ }
173
+
174
+ // 周期性外部世界演化:让 mac-ext-02 每 15s 领一个新作业
175
+ setInterval(() => {
176
+ const inst = instances.find((i) => i.name === "mac-ext-02");
177
+ if (!inst || inst.processState !== "running" || inst.currentJob) return;
178
+ const jobs = ["build-mac", "publish-feed", "deploy"];
179
+ const job = jobs[Math.floor(Math.random() * jobs.length)];
180
+ inst.currentJob = { job, startedAt: new Date().toISOString() };
181
+ addLog(inst, ts() + ` Running job: ${job}`);
182
+ sink();
183
+ setTimeout(() => {
184
+ if (!inst.currentJob) return;
185
+ const ok = job !== "publish-feed";
186
+ inst.lastResult = { job, outcome: ok ? "Succeeded" : "Failed", at: new Date().toISOString(), durationMs: 95_000 };
187
+ addLog(inst, ts() + ` Job ${job} completed with result: ${inst.lastResult.outcome}`);
188
+ inst.currentJob = null;
189
+ sink();
190
+ }, 9000);
191
+ }, 15000);
192
+
193
+ sink();
194
+ })();