mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-16 16:16:32 +03:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40e050afda |
@@ -1093,26 +1093,12 @@ fn extract_inner_by_attr(text: &str, attr: &str) -> Option<String> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drop leading and trailing blank lines while keeping a single empty line
|
|
||||||
/// when the inner text is only whitespace.
|
|
||||||
fn trim_surrounding_blank_lines(lines: Vec<String>) -> Vec<String> {
|
|
||||||
let mut start = 0usize;
|
|
||||||
let mut end = lines.len();
|
|
||||||
while end - start > 1 && trim(&lines[start]).is_empty() {
|
|
||||||
start += 1;
|
|
||||||
}
|
|
||||||
while end - start > 1 && trim(&lines[end - 1]).is_empty() {
|
|
||||||
end -= 1;
|
|
||||||
}
|
|
||||||
lines[start..end].to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// JS: extractOriginal(lines, block)
|
/// JS: extractOriginal(lines, block)
|
||||||
fn extract_original(lines: &[String], block: &MarkerBlock) -> Vec<String> {
|
fn extract_original(lines: &[String], block: &MarkerBlock) -> Vec<String> {
|
||||||
let text = strip_style_and_join(lines, block);
|
let text = strip_style_and_join(lines, block);
|
||||||
match extract_inner_by_attr(&text, "data-impeccable-variant=\"original\"") {
|
match extract_inner_by_attr(&text, "data-impeccable-variant=\"original\"") {
|
||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
Some(inner) => trim_surrounding_blank_lines(inner.split('\n').map(String::from).collect()),
|
Some(inner) => inner.split('\n').map(String::from).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1127,7 +1113,13 @@ fn extract_variant(
|
|||||||
&text,
|
&text,
|
||||||
&format!("data-impeccable-variant=\"{}\"", variant_num),
|
&format!("data-impeccable-variant=\"{}\"", variant_num),
|
||||||
)?;
|
)?;
|
||||||
let result = trim_surrounding_blank_lines(inner.split('\n').map(String::from).collect());
|
let mut result: Vec<String> = inner.split('\n').map(String::from).collect();
|
||||||
|
while result.len() > 1 && trim(&result[0]).is_empty() {
|
||||||
|
result.remove(0);
|
||||||
|
}
|
||||||
|
while result.len() > 1 && trim(result.last().unwrap()).is_empty() {
|
||||||
|
result.pop();
|
||||||
|
}
|
||||||
if result.is_empty() {
|
if result.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@@ -1257,55 +1249,6 @@ fn find_session_file(id: &str, cwd: &str) -> Option<(String, String, Vec<String>
|
|||||||
Some((file, content, lines))
|
Some((file, content, lines))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod discard_tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn discard_restores_the_original_without_blank_lines_around_it() {
|
|
||||||
let nanos = std::time::SystemTime::now()
|
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
|
||||||
.map(|d| d.as_nanos())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let dir = std::env::temp_dir().join(format!(
|
|
||||||
"impeccable-discard-{}-{nanos}",
|
|
||||||
std::process::id()
|
|
||||||
));
|
|
||||||
let _ = std::fs::remove_dir_all(&dir);
|
|
||||||
std::fs::create_dir_all(&dir).unwrap();
|
|
||||||
let file = dir.join("Login.tsx");
|
|
||||||
let src = [
|
|
||||||
" </div>",
|
|
||||||
" <div data-impeccable-variants=\"ab12cd34\" data-impeccable-variant-count=\"3\" style={{ display: \"contents\" }}>",
|
|
||||||
" {/* impeccable-variants-start ab12cd34 */}",
|
|
||||||
" <style data-impeccable-css=\"ab12cd34\">{`",
|
|
||||||
" @scope ([data-impeccable-variant=\"1\"]) { :scope > .x { color: red; } }",
|
|
||||||
" `}</style>",
|
|
||||||
" {/* Original */}",
|
|
||||||
" <div data-impeccable-variant=\"original\">",
|
|
||||||
" <Bar title=\"Log in\" />",
|
|
||||||
" </div>",
|
|
||||||
" {/* Variants: insert below this line */}",
|
|
||||||
" <div data-impeccable-variant=\"1\">",
|
|
||||||
" <Bar title=\"Log in\" />",
|
|
||||||
" </div>",
|
|
||||||
" {/* impeccable-variants-end ab12cd34 */}",
|
|
||||||
" </div>",
|
|
||||||
" </AuthPage>",
|
|
||||||
];
|
|
||||||
let lines: Vec<String> = src.iter().map(|s| s.to_string()).collect();
|
|
||||||
let path = file.to_string_lossy().into_owned();
|
|
||||||
std::fs::write(&file, lines.join("\n")).unwrap();
|
|
||||||
handle_discard_unlocked("ab12cd34", &lines, &path).unwrap();
|
|
||||||
let out = std::fs::read_to_string(&file).unwrap();
|
|
||||||
let _ = std::fs::remove_dir_all(&dir);
|
|
||||||
assert_eq!(
|
|
||||||
out,
|
|
||||||
" </div>\n <Bar title=\"Log in\" />\n </AuthPage>"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod bake_tests {
|
mod bake_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -140,25 +140,26 @@ fn locale_compare(a: &str, b: &str) -> std::cmp::Ordering {
|
|||||||
fn check(io: &mut Io) -> R<()> {
|
fn check(io: &mut Io) -> R<()> {
|
||||||
let (sys, _) = ctx(io);
|
let (sys, _) = ctx(io);
|
||||||
let root = sys.find_project_root();
|
let root = sys.find_project_root();
|
||||||
if sys.is_already_installed(&root, None).is_none() {
|
// A home-rooted check is the user-level equivalent of `update --global`.
|
||||||
|
// Keep both verbs on the canonical provider paths so stale legacy paths
|
||||||
|
// (for example ~/.pi/skills) cannot make only `check` report drift.
|
||||||
|
let scope = if sys.is_home_dir(&root) { Some(Scope::User) } else { None };
|
||||||
|
if sys.is_already_installed(&root, scope).is_none() {
|
||||||
out(io, "Impeccable is not installed in this project.");
|
out(io, "Impeccable is not installed in this project.");
|
||||||
out(io, "Run `npx impeccable install` to install.");
|
out(io, "Run `npx impeccable install` to install.");
|
||||||
return Err(Flow::Exit(0));
|
return Err(Flow::Exit(0));
|
||||||
}
|
}
|
||||||
let providers = sys.find_installed_providers(&root, None);
|
let providers = sys.find_installed_providers(&root, scope);
|
||||||
out(io, "Checking for updates...\n");
|
out(io, "Checking for updates...\n");
|
||||||
let result = (|| -> Result<bool, String> {
|
let result = (|| -> Result<bool, String> {
|
||||||
let bundle_dir = bundle::download_and_extract_bundle(&sys)?;
|
let bundle_dir = bundle::download_and_extract_bundle(&sys)?;
|
||||||
// JS: agentScope 'user' for a home-rooted checkout (d2a9efb9), so
|
let up_to_date = bundle::is_up_to_date(&sys, &root, &providers, &bundle_dir, scope, scope)?;
|
||||||
// check() judges agent freshness against the user agent dirs.
|
|
||||||
let agent_scope = if sys.is_home_dir(&root) { Some(Scope::User) } else { None };
|
|
||||||
let up_to_date = bundle::is_up_to_date(&sys, &root, &providers, &bundle_dir, None, agent_scope)?;
|
|
||||||
util::rm_rf(&bundle_dir);
|
util::rm_rf(&bundle_dir);
|
||||||
Ok(up_to_date)
|
Ok(up_to_date)
|
||||||
})();
|
})();
|
||||||
match result {
|
match result {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
let v = sys.get_skills_version(&root, None);
|
let v = sys.get_skills_version(&root, scope);
|
||||||
out(io, &format!("Skills are up to date{}.", version_suffix(&v)));
|
out(io, &format!("Skills are up to date{}.", version_suffix(&v)));
|
||||||
}
|
}
|
||||||
Ok(false) => {
|
Ok(false) => {
|
||||||
|
|||||||
@@ -460,6 +460,40 @@ fn check_accepts_current_copilot_user_agents_in_home_rooted_checkout() {
|
|||||||
std::fs::remove_dir_all(&root).ok();
|
std::fs::remove_dir_all(&root).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_ignores_stale_legacy_pi_skills_when_the_user_install_is_current() {
|
||||||
|
let root = temp_root("pi-check-home-scope");
|
||||||
|
let home = format!("{root}/home");
|
||||||
|
let tmpdir = format!("{root}/tmp");
|
||||||
|
for d in [&home, &tmpdir] {
|
||||||
|
std::fs::create_dir_all(d).unwrap();
|
||||||
|
}
|
||||||
|
let bundle_root = create_fake_universal_bundle(&root, &[".pi"]);
|
||||||
|
let env = base_env(&home, &tmpdir, &bundle_root);
|
||||||
|
|
||||||
|
let r = run_cli(
|
||||||
|
&["install", "-y", "--scope=global", "--no-hooks", "--providers=pi"],
|
||||||
|
&home,
|
||||||
|
&env,
|
||||||
|
);
|
||||||
|
assert_eq!(r.code, 0, "{}\n{}", r.stdout, r.stderr);
|
||||||
|
|
||||||
|
let canonical = format!("{home}/.pi/agent/skills/impeccable");
|
||||||
|
let legacy = format!("{home}/.pi/skills/impeccable");
|
||||||
|
std::fs::create_dir_all(format!("{home}/.pi/skills")).unwrap();
|
||||||
|
std::fs::create_dir_all(&legacy).unwrap();
|
||||||
|
write(&format!("{legacy}/SKILL.md"), "---\nname: impeccable\nversion: 1.0.0-stale\n---\n");
|
||||||
|
assert!(std::path::Path::new(&canonical).exists());
|
||||||
|
|
||||||
|
let update = run_cli(&["update", "--global", "-y", "--no-hooks"], &home, &env);
|
||||||
|
assert!(update.stdout.contains("Skills are up to date"), "{}\n{}", update.stdout, update.stderr);
|
||||||
|
|
||||||
|
let check = run_cli(&["check"], &home, &env);
|
||||||
|
assert!(check.stdout.contains("Skills are up to date"), "{}\n{}", check.stdout, check.stderr);
|
||||||
|
assert!(!check.stdout.contains("Updates available"), "{}", check.stdout);
|
||||||
|
std::fs::remove_dir_all(&root).ok();
|
||||||
|
}
|
||||||
|
|
||||||
// ─── inferred agent update scope (d2a9efb9) ──────────────────────────────────
|
// ─── inferred agent update scope (d2a9efb9) ──────────────────────────────────
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ retain their local-development trust behavior. See [bundle signing](BUNDLE-SIGNI
|
|||||||
Already installed (and not `--force`): `Impeccable skills are already installed (found in ${provider}/).`; compares tree hashes (`sha256` of file content with `\.(claude|cursor|...)\/skills\/` normalized to `.PROVIDER/skills/`); if differs → refresh + `Updated ${n} skill(s) to v${v}.`; missing hooks repaired; else `Skills are up to date (v${v}).` + `Run with --force to reinstall.`; offline → `Could not check for skill updates: ${msg}` + `Existing skills were left unchanged.`; ends `Done!` or the above; `exit 0`. Version read from `^version:\s*(.+)$` in installed `impeccable/SKILL.md`.
|
Already installed (and not `--force`): `Impeccable skills are already installed (found in ${provider}/).`; compares tree hashes (`sha256` of file content with `\.(claude|cursor|...)\/skills\/` normalized to `.PROVIDER/skills/`); if differs → refresh + `Updated ${n} skill(s) to v${v}.`; missing hooks repaired; else `Skills are up to date (v${v}).` + `Run with --force to reinstall.`; offline → `Could not check for skill updates: ${msg}` + `Existing skills were left unchanged.`; ends `Done!` or the above; `exit 0`. Version read from `^version:\s*(.+)$` in installed `impeccable/SKILL.md`.
|
||||||
- **update flags**: `-y|--yes`, `--force`, `--no-hooks`, scope flags as above (unknown → `Unknown update scope: ${v}. Use --project or --user.`). Resolves project vs user installs holding an `impeccable`/`*-impeccable`/`teach-impeccable` skill; none → `No impeccable skill folders found in this project or at the user level.` + `Run \`npx impeccable install\` to install first.`, exit 1; both → prompt `Update which? [project]/user: ` (non-TTY defaults project). Prints `Updating the ${label} install: ${root} (${providers})`, linked providers note, `Checking for updates...`; up to date → `Skills are up to date (vX).` [+hooks] + `Nothing else to do.`, exit 0; else `Found skills in: ...`, prompt `Update skills in N provider folder(s)? (Y/n) ` (n/no → `Aborted.` exit 0), refresh, `Updated N skill(s) to vX.`, `Done!`.
|
- **update flags**: `-y|--yes`, `--force`, `--no-hooks`, scope flags as above (unknown → `Unknown update scope: ${v}. Use --project or --user.`). Resolves project vs user installs holding an `impeccable`/`*-impeccable`/`teach-impeccable` skill; none → `No impeccable skill folders found in this project or at the user level.` + `Run \`npx impeccable install\` to install first.`, exit 1; both → prompt `Update which? [project]/user: ` (non-TTY defaults project). Prints `Updating the ${label} install: ${root} (${providers})`, linked providers note, `Checking for updates...`; up to date → `Skills are up to date (vX).` [+hooks] + `Nothing else to do.`, exit 0; else `Found skills in: ...`, prompt `Update skills in N provider folder(s)? (Y/n) ` (n/no → `Aborted.` exit 0), refresh, `Updated N skill(s) to vX.`, `Done!`.
|
||||||
- **link**: `--source=<path>` (default `.impeccable`), `--providers`, `--force`, `-y`. Source must contain `dist/universal/` or provider `*/skills` dirs, else `Could not find compiled skills in ${src}. Expected dist/universal/ or provider skill folders.` Prompts `Link impeccable skills into N folder(s)? (Y/n) `; creates relative dir symlinks; existing non-link skipped with warning unless `--force`; output `Linked impeccable into: ... (N linked, N already linked, N skipped).` + submodule hint.
|
- **link**: `--source=<path>` (default `.impeccable`), `--providers`, `--force`, `-y`. Source must contain `dist/universal/` or provider `*/skills` dirs, else `Could not find compiled skills in ${src}. Expected dist/universal/ or provider skill folders.` Prompts `Link impeccable skills into N folder(s)? (Y/n) `; creates relative dir symlinks; existing non-link skipped with warning unless `--force`; output `Linked impeccable into: ... (N linked, N already linked, N skipped).` + submodule hint.
|
||||||
- **check**: not installed → `Impeccable is not installed in this project.` + `Run \`npx impeccable install\` to install.` exit 0; else `Checking for updates...\n` then `Skills are up to date (vX).` or `Updates available.` + `Run \`npx impeccable update\` to update.`; failure → `Could not check for updates: ${msg}` exit 1.
|
- **check**: not installed → `Impeccable is not installed in this project.` + `Run \`npx impeccable install\` to install.` exit 0; else `Checking for updates...\n` then `Skills are up to date (vX).` or `Updates available.` + `Run \`npx impeccable update\` to update.`; failure → `Could not check for updates: ${msg}` exit 1. A home-rooted check uses user scope, matching `update --global`: provider-specific canonical global paths are compared, while stale legacy duplicates such as `~/.pi/skills` do not create false update notices.
|
||||||
- Prompts: non-TTY `ask()` reads answers line-by-line from stdin (fd 0) after echoing the question; TTY SIGINT → `PromptAbortError` (`code IMPECCABLE_PROMPT_ABORT`) → cli.js prints `\nAborted.` exit 130. ANSI (`\x1b[36m` accent, `\x1b[1m` bold, `\x1b[2m` dim, `\x1b[32m` good) only when stdout is TTY, `NO_COLOR` unset, `TERM !== 'dumb'`.
|
- Prompts: non-TTY `ask()` reads answers line-by-line from stdin (fd 0) after echoing the question; TTY SIGINT → `PromptAbortError` (`code IMPECCABLE_PROMPT_ABORT`) → cli.js prints `\nAborted.` exit 130. ANSI (`\x1b[36m` accent, `\x1b[1m` bold, `\x1b[2m` dim, `\x1b[32m` good) only when stdout is TTY, `NO_COLOR` unset, `TERM !== 'dumb'`.
|
||||||
- Tests: `tests/skills-cli.test.js`, `tests/cli-remote-e2e` (opt-in).
|
- Tests: `tests/skills-cli.test.js`, `tests/cli-remote-e2e` (opt-in).
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,6 @@
|
|||||||
"files": {
|
"files": {
|
||||||
".impeccable/live/accept-receipts/ab12cd34.json": "{\n \"id\": \"ab12cd34\",\n \"operation\": \"discard\",\n \"variantId\": null,\n \"result\": {\n \"handled\": true,\n \"file\": \"index.html\",\n \"carbonize\": false\n },\n \"completedAt\": \"<ISO>\"\n}\n",
|
".impeccable/live/accept-receipts/ab12cd34.json": "{\n \"id\": \"ab12cd34\",\n \"operation\": \"discard\",\n \"variantId\": null,\n \"result\": {\n \"handled\": true,\n \"file\": \"index.html\",\n \"carbonize\": false\n },\n \"completedAt\": \"<ISO>\"\n}\n",
|
||||||
".impeccable/live/config.json": "{\n \"files\": [\"index.html\", \"public/**/*.html\"],\n \"insertBefore\": \"</body>\",\n \"commentSyntax\": \"html\"\n}\n",
|
".impeccable/live/config.json": "{\n \"files\": [\"index.html\", \"public/**/*.html\"],\n \"insertBefore\": \"</body>\",\n \"commentSyntax\": \"html\"\n}\n",
|
||||||
"index.html": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Oracle Live HTML Fixture</title>\n <style>\n .hero-title { font-size: 2rem; }\n .hero-hook { color: #555; }\n </style>\n </head>\n <body>\n <main class=\"page\">\n <h1 id=\"hero\" class=\"hero-title\">Oracle Fixture</h1>\n <p class=\"hero-hook\">Minimal static page for oracle live-mode goldens.</p>\n <section id=\"features\" class=\"feature-grid\">\n <article class=\"feature-card\">One</article>\n <article class=\"feature-card\">Two</article>\n </section>\n <aside class=\"side-note\">\n <h2 class=\"note-title\">Aside</h2>\n <p>Nested content.</p>\n </aside>\n </main>\n </body>\n</html>\n"
|
"index.html": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Oracle Live HTML Fixture</title>\n <style>\n .hero-title { font-size: 2rem; }\n .hero-hook { color: #555; }\n </style>\n </head>\n <body>\n <main class=\"page\">\n\n <h1 id=\"hero\" class=\"hero-title\">Oracle Fixture</h1>\n\n <p class=\"hero-hook\">Minimal static page for oracle live-mode goldens.</p>\n <section id=\"features\" class=\"feature-grid\">\n <article class=\"feature-card\">One</article>\n <article class=\"feature-card\">Two</article>\n </section>\n <aside class=\"side-note\">\n <h2 class=\"note-title\">Aside</h2>\n <p>Nested content.</p>\n </aside>\n </main>\n </body>\n</html>\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,6 @@
|
|||||||
"files": {
|
"files": {
|
||||||
".impeccable/live/accept-receipts/ab12cd34.json": "{\n \"id\": \"ab12cd34\",\n \"operation\": \"discard\",\n \"variantId\": null,\n \"result\": {\n \"handled\": true,\n \"file\": \"index.html\",\n \"carbonize\": false\n },\n \"completedAt\": \"<ISO>\"\n}\n",
|
".impeccable/live/accept-receipts/ab12cd34.json": "{\n \"id\": \"ab12cd34\",\n \"operation\": \"discard\",\n \"variantId\": null,\n \"result\": {\n \"handled\": true,\n \"file\": \"index.html\",\n \"carbonize\": false\n },\n \"completedAt\": \"<ISO>\"\n}\n",
|
||||||
".impeccable/live/config.json": "{\n \"files\": [\"index.html\", \"public/**/*.html\"],\n \"insertBefore\": \"</body>\",\n \"commentSyntax\": \"html\"\n}\n",
|
".impeccable/live/config.json": "{\n \"files\": [\"index.html\", \"public/**/*.html\"],\n \"insertBefore\": \"</body>\",\n \"commentSyntax\": \"html\"\n}\n",
|
||||||
"index.html": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Oracle Live HTML Fixture</title>\n <style>\n .hero-title { font-size: 2rem; }\n .hero-hook { color: #555; }\n </style>\n </head>\n <body>\n <main class=\"page\">\n <h1 id=\"hero\" class=\"hero-title\">Oracle Fixture</h1>\n <p class=\"hero-hook\">Minimal static page for oracle live-mode goldens.</p>\n <section id=\"features\" class=\"feature-grid\">\n <article class=\"feature-card\">One</article>\n <article class=\"feature-card\">Two</article>\n </section>\n <aside class=\"side-note\">\n <h2 class=\"note-title\">Aside</h2>\n <p>Nested content.</p>\n </aside>\n </main>\n </body>\n</html>\n"
|
"index.html": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Oracle Live HTML Fixture</title>\n <style>\n .hero-title { font-size: 2rem; }\n .hero-hook { color: #555; }\n </style>\n </head>\n <body>\n <main class=\"page\">\n\n <h1 id=\"hero\" class=\"hero-title\">Oracle Fixture</h1>\n\n <p class=\"hero-hook\">Minimal static page for oracle live-mode goldens.</p>\n <section id=\"features\" class=\"feature-grid\">\n <article class=\"feature-card\">One</article>\n <article class=\"feature-card\">Two</article>\n </section>\n <aside class=\"side-note\">\n <h2 class=\"note-title\">Aside</h2>\n <p>Nested content.</p>\n </aside>\n </main>\n </body>\n</html>\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"files": {
|
"files": {
|
||||||
".impeccable/live/accept-receipts/ab12cd34.json": "{\n \"id\": \"ab12cd34\",\n \"operation\": \"discard\",\n \"variantId\": null,\n \"result\": {\n \"handled\": true,\n \"file\": \"src/App.jsx\",\n \"carbonize\": false\n },\n \"completedAt\": \"<ISO>\"\n}\n",
|
".impeccable/live/accept-receipts/ab12cd34.json": "{\n \"id\": \"ab12cd34\",\n \"operation\": \"discard\",\n \"variantId\": null,\n \"result\": {\n \"handled\": true,\n \"file\": \"src/App.jsx\",\n \"carbonize\": false\n },\n \"completedAt\": \"<ISO>\"\n}\n",
|
||||||
".impeccable/live/config.json": "{\n \"files\": [\"index.html\"],\n \"insertBefore\": \"</body>\",\n \"commentSyntax\": \"html\"\n}\n",
|
".impeccable/live/config.json": "{\n \"files\": [\"index.html\"],\n \"insertBefore\": \"</body>\",\n \"commentSyntax\": \"html\"\n}\n",
|
||||||
"src/App.jsx": "export default function App() {\n return (\n <main className=\"page\">\n <h1 className=\"hero-title\">Vite Fixture</h1>\n <p className=\"hero-hook\">Minimal React tree for oracle live-mode goldens.</p>\n <section id=\"features\" className=\"feature-grid\">\n <article className=\"feature-card\">One</article>\n <article className=\"feature-card\">Two</article>\n </section>\n <ul className=\"item-list\">\n {items.map((item) => (\n <li key={item.id} className=\"item-row\">{item.title}</li>\n ))}\n </ul>\n </main>\n );\n}\n\nconst items = [\n { id: 1, title: 'First' },\n { id: 2, title: 'Second' },\n];\n",
|
"src/App.jsx": "export default function App() {\n return (\n <main className=\"page\">\n\n <h1 className=\"hero-title\">Vite Fixture</h1>\n\n <p className=\"hero-hook\">Minimal React tree for oracle live-mode goldens.</p>\n <section id=\"features\" className=\"feature-grid\">\n <article className=\"feature-card\">One</article>\n <article className=\"feature-card\">Two</article>\n </section>\n <ul className=\"item-list\">\n {items.map((item) => (\n <li key={item.id} className=\"item-row\">{item.title}</li>\n ))}\n </ul>\n </main>\n );\n}\n\nconst items = [\n { id: 1, title: 'First' },\n { id: 2, title: 'Second' },\n];\n",
|
||||||
"src/main.jsx": "import { createRoot } from 'react-dom/client';\nimport App from './App.jsx';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n",
|
"src/main.jsx": "import { createRoot } from 'react-dom/client';\nimport App from './App.jsx';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n",
|
||||||
"src/Panel.tsx": "type PanelProps = { title: string; children?: React.ReactNode };\n\nexport function Panel({ title, children }: PanelProps) {\n return (\n <section className=\"panel\">\n <header className=\"panel-header\">\n <h2 className=\"panel-title\">{title}</h2>\n </header>\n <div className=\"panel-body\">{children}</div>\n </section>\n );\n}\n"
|
"src/Panel.tsx": "type PanelProps = { title: string; children?: React.ReactNode };\n\nexport function Panel({ title, children }: PanelProps) {\n return (\n <section className=\"panel\">\n <header className=\"panel-header\">\n <h2 className=\"panel-title\">{title}</h2>\n </header>\n <div className=\"panel-body\">{children}</div>\n </section>\n );\n}\n"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,6 @@
|
|||||||
".impeccable/live/accept-receipts/ab12cd34.json": "{\n \"id\": \"ab12cd34\",\n \"operation\": \"discard\",\n \"variantId\": null,\n \"result\": {\n \"handled\": true,\n \"file\": \"src/routes/+page.svelte\",\n \"carbonize\": false\n },\n \"completedAt\": \"<ISO>\"\n}\n",
|
".impeccable/live/accept-receipts/ab12cd34.json": "{\n \"id\": \"ab12cd34\",\n \"operation\": \"discard\",\n \"variantId\": null,\n \"result\": {\n \"handled\": true,\n \"file\": \"src/routes/+page.svelte\",\n \"carbonize\": false\n },\n \"completedAt\": \"<ISO>\"\n}\n",
|
||||||
".impeccable/live/config.json": "{\n \"files\": [\"src/app.html\"],\n \"insertBefore\": \"</body>\",\n \"commentSyntax\": \"html\"\n}\n",
|
".impeccable/live/config.json": "{\n \"files\": [\"src/app.html\"],\n \"insertBefore\": \"</body>\",\n \"commentSyntax\": \"html\"\n}\n",
|
||||||
"src/app.html": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>SvelteKit Fixture</title>\n %sveltekit.head%\n </head>\n <body data-sveltekit-preload-data=\"hover\">\n <div style=\"display: contents\">%sveltekit.body%</div>\n </body>\n</html>\n",
|
"src/app.html": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>SvelteKit Fixture</title>\n %sveltekit.head%\n </head>\n <body data-sveltekit-preload-data=\"hover\">\n <div style=\"display: contents\">%sveltekit.body%</div>\n </body>\n</html>\n",
|
||||||
"src/routes/+page.svelte": "<script>\n let title = 'SvelteKit Fixture';\n let expenses = [\n { id: 1, label: 'Coffee', amount: 3 },\n { id: 2, label: 'Lunch', amount: 12 },\n ];\n</script>\n\n<main class=\"page\">\n <h1 class=\"hero-title\">{title}</h1>\n <p class=\"hero-hook\">Minimal SvelteKit route for oracle live-mode goldens.</p>\n <ul class=\"expense-list\">\n {#each expenses as expense (expense.id)}\n <li class=\"expense-row\">{expense.label}: {expense.amount}</li>\n {/each}\n </ul>\n <section id=\"features\" class=\"feature-grid\">\n <article class=\"feature-card\">One</article>\n <article class=\"feature-card\">Two</article>\n </section>\n</main>\n\n<style>\n .hero-title { font-size: 2rem; }\n .expense-list { list-style: none; padding: 0; }\n .expense-row { padding: 4px 0; }\n</style>\n"
|
"src/routes/+page.svelte": "<script>\n let title = 'SvelteKit Fixture';\n let expenses = [\n { id: 1, label: 'Coffee', amount: 3 },\n { id: 2, label: 'Lunch', amount: 12 },\n ];\n</script>\n\n<main class=\"page\">\n\n <h1 class=\"hero-title\">{title}</h1>\n\n <p class=\"hero-hook\">Minimal SvelteKit route for oracle live-mode goldens.</p>\n <ul class=\"expense-list\">\n {#each expenses as expense (expense.id)}\n <li class=\"expense-row\">{expense.label}: {expense.amount}</li>\n {/each}\n </ul>\n <section id=\"features\" class=\"feature-grid\">\n <article class=\"feature-card\">One</article>\n <article class=\"feature-card\">Two</article>\n </section>\n</main>\n\n<style>\n .hero-title { font-size: 2rem; }\n .expense-list { list-style: none; padding: 0; }\n .expense-row { padding: 4px 0; }\n</style>\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user