instar 0.6.7 → 0.6.8
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/server/routes.js +58 -0
- package/package.json +1 -1
package/dist/server/routes.js
CHANGED
|
@@ -173,6 +173,64 @@ export function createRoutes(ctx) {
|
|
|
173
173
|
monitoring: ctx.config.monitoring,
|
|
174
174
|
});
|
|
175
175
|
});
|
|
176
|
+
// ── CI Health ─────────────────────────────────────────────────────
|
|
177
|
+
//
|
|
178
|
+
// On-demand CI status check. Detects GitHub repo from git remote and
|
|
179
|
+
// queries GitHub Actions for recent failures. Agents can use this to
|
|
180
|
+
// check CI health without waiting for the next self-diagnosis cycle.
|
|
181
|
+
router.get('/ci', (_req, res) => {
|
|
182
|
+
const projectDir = ctx.config.projectDir;
|
|
183
|
+
// Detect GitHub repo from git remote
|
|
184
|
+
let repo = null;
|
|
185
|
+
try {
|
|
186
|
+
const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], {
|
|
187
|
+
cwd: projectDir,
|
|
188
|
+
encoding: 'utf-8',
|
|
189
|
+
timeout: 5000,
|
|
190
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
191
|
+
}).trim();
|
|
192
|
+
// Extract owner/repo from SSH or HTTPS URL
|
|
193
|
+
const match = remoteUrl.match(/github\.com[:/](.+?)(?:\.git)?$/);
|
|
194
|
+
if (match)
|
|
195
|
+
repo = match[1];
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// Not a git repo or no remote
|
|
199
|
+
}
|
|
200
|
+
if (!repo) {
|
|
201
|
+
res.json({ status: 'unknown', message: 'No GitHub repo detected', runs: [] });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// Query recent CI runs
|
|
205
|
+
try {
|
|
206
|
+
const result = execFileSync('gh', [
|
|
207
|
+
'run', 'list', '--repo', repo, '--limit', '5',
|
|
208
|
+
'--json', 'databaseId,conclusion,status,headBranch,name,createdAt',
|
|
209
|
+
], {
|
|
210
|
+
encoding: 'utf-8',
|
|
211
|
+
timeout: 15000,
|
|
212
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
213
|
+
});
|
|
214
|
+
const runs = JSON.parse(result);
|
|
215
|
+
const failures = runs.filter((r) => r.conclusion === 'failure');
|
|
216
|
+
const inProgress = runs.filter((r) => r.status === 'in_progress');
|
|
217
|
+
res.json({
|
|
218
|
+
repo,
|
|
219
|
+
status: failures.length > 0 ? 'failing' : inProgress.length > 0 ? 'in_progress' : 'passing',
|
|
220
|
+
failureCount: failures.length,
|
|
221
|
+
inProgressCount: inProgress.length,
|
|
222
|
+
runs,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
res.json({
|
|
227
|
+
repo,
|
|
228
|
+
status: 'error',
|
|
229
|
+
message: err instanceof Error ? err.message : 'gh CLI failed',
|
|
230
|
+
runs: [],
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
});
|
|
176
234
|
// ── Sessions ────────────────────────────────────────────────────
|
|
177
235
|
// Literal routes BEFORE parameterized routes to avoid capture
|
|
178
236
|
router.get('/sessions/tmux', (_req, res) => {
|