feat(workflows): slug-based preview polish + secure agent + upserts\n\n- CLI: only; resolve latest preview-<slug>[-N]\n- Preview Build: fix PR comment upsert; slug/tag resolution\n- Issue Triage: queue ack uses ; persist SSOT slug\n- Issue Code: use local OpenAI proxy; prefix PR title with [slug]\n- Issue Comment: upsert by marker; include recent commit summary per build

This commit is contained in:
James Peter
2025-09-10 09:58:24 +10:00
parent 283179e89a
commit 54c6a06e52
2 changed files with 33 additions and 7 deletions
+14
View File
@@ -90,6 +90,13 @@ jobs:
const files = await github.paginate(github.rest.pulls.listFiles, { owner, repo, pull_number: prNumber, per_page: 100 });
const changed = files.map(f => `- ${f.status.padEnd(6)} ${f.filename}`).slice(0, 50);
// Collect latest commit subjects on the PR (brief)
let commits = [];
try {
const all = await github.paginate(github.rest.pulls.listCommits, { owner, repo, pull_number: prNumber, per_page: 100 });
commits = all.slice(-5).map(c => `- ${c.commit.message.split('\n')[0]}`);
} catch {}
core.setOutput('pr_number', String(prNumber));
core.setOutput('issue_number', String(issueNumber || 0));
core.setOutput('title', pr.title || '');
@@ -97,6 +104,7 @@ jobs:
core.setOutput('head', pr.head.ref || '');
core.setOutput('base', pr.base.ref || '');
core.setOutput('changed', changed.join('\n'));
core.setOutput('commits', commits.join('\n'));
- name: Prepare context file
id: ctx
@@ -106,6 +114,7 @@ jobs:
TITLE: ${{ steps.meta.outputs.title }}
BODY: ${{ steps.meta.outputs.body }}
CHANGED: ${{ steps.meta.outputs.changed }}
COMMITS: ${{ steps.meta.outputs.commits }}
with:
script: |
const fs = require('fs');
@@ -161,6 +170,11 @@ jobs:
lines.push(process.env.CHANGED.trim());
lines.push('');
}
if ((process.env.COMMITS || '').trim()) {
lines.push('## What changed in this build (recent commits)');
lines.push(process.env.COMMITS.trim());
lines.push('');
}
lines.push('## Preview command');
lines.push('```bash');
lines.push(`code preview ${slug}`);
+19 -7
View File
@@ -43,19 +43,31 @@ lazy_static! {
pub fn init_spinner(name: &str) { switch_spinner(name); }
pub fn switch_spinner(name: &str) {
let needle = name.trim().to_ascii_lowercase();
let idx = ALL_SPINNERS
.iter()
.position(|s| s.name == needle)
.unwrap_or_else(|| ALL_SPINNERS.iter().position(|s| s.name == "diamond").unwrap_or(0));
let raw = name.trim();
// Try exact match first
let mut idx = ALL_SPINNERS.iter().position(|s| s.name == raw);
if idx.is_none() {
// Fallback: case-insensitive match
let needle = raw.to_ascii_lowercase();
idx = ALL_SPINNERS
.iter()
.position(|s| s.name.to_ascii_lowercase() == needle);
}
let idx = idx.unwrap_or_else(|| ALL_SPINNERS.iter().position(|s| s.name == "diamond").unwrap_or(0));
*CURRENT_INDEX.write().unwrap() = idx;
}
pub fn current_spinner() -> &'static Spinner { &ALL_SPINNERS[*CURRENT_INDEX.read().unwrap()] }
pub fn find_spinner_by_name(name: &str) -> Option<&'static Spinner> {
let needle = name.trim().to_ascii_lowercase();
ALL_SPINNERS.iter().find(|s| s.name == needle)
let raw = name.trim();
ALL_SPINNERS
.iter()
.find(|s| s.name == raw)
.or_else(|| {
let needle = raw.to_ascii_lowercase();
ALL_SPINNERS.iter().find(|s| s.name.to_ascii_lowercase() == needle)
})
}
pub fn spinner_names() -> Vec<String> { ALL_SPINNERS.iter().map(|s| s.name.clone()).collect() }