Commit Graph
2190 Commits
Author SHA1 Message Date
github-actions[bot] 853ca5ce3b chore: bump version to 1.9.4 [skip ci] 2026-08-22 18:55:56 +00:00
Juan Denis c756b61abe Merge remote-tracking branch 'origin/main' into dev 2026-08-22 14:49:20 -04:00
Juan Denis dd59a84619 fix(ci): keep version bumps behind green checks 2026-08-22 14:49:12 -04:00
Juan Denis 1fad04e880 fix(recipes): restore CI boundary contracts 2026-08-22 14:49:11 -04:00
github-actions[bot] ab0c3174b0 chore: bump version to 1.9.3 [skip ci] 2026-08-22 18:25:23 +00:00
Juan DenisandClaude Fable 5 2a5d18867f refactor(walkthroughs): the shell dock says Walkthroughs, not Recipes
Reserve the word Recipes for installers. The status-bar segment, dock
tab, hub aria-label and command-palette category now read Walkthroughs
(new app.walkthroughs.title/all keys; stale es allRecipes dropped).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 14:21:04 -04:00
Juan DenisandClaude Fable 5 93c8abbbbe feat(recipes): serverkit-recipes registry catalog with one-call installs
The curated serverkit-recipes index is consumed like the themes registry
(cached remote index, bundled fallback, SERVERKIT_RECIPES_REGISTRY_URL
override). GET /recipes/registry[/<slug>] browses it; POST /recipes/runs
now accepts a registry_slug plus server_id — targeting a server finds or
creates the per-workspace Recipes project — and validated non-secret
params that pre-supply handoff inputs so only true secrets pause the run.

Frontend: Recipes catalog page (cards, category chips, install drawer
with running-server picker, preflight table, up-front inputs and an
asked-during-the-run secrets preview) under new Services and Marketplace
tabs; runs land in the deployment console.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 14:20:55 -04:00
github-actions[bot] 82dc866c41 chore: bump version to 1.9.2 [skip ci] 2026-08-22 06:55:21 +00:00
Juan DenisandClaude Fable 5 d867b92c98 chore(i18n): sync locales for the shell console round
en.json regenerated from inline defaults (new statusbar/console/palette/
recipes strings; Prompture and old walkthrough-hub strings gone). es picks
up translations for all 26 new keys; every locale drops the now-orphaned
keys so the parity gate stays green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 02:43:38 -04:00
Juan DenisandClaude Fable 5 adf6b48bff style(buttons): prototype accent treatment for the primary button
Gradient fill (accent-bright to accent), accent glow, inner top highlight,
and a hover that lifts the gradient toward white — all from theme tokens so
runtime skins keep recoloring it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 02:43:27 -04:00
Juan DenisandClaude Fable 5 8b7cecb62e feat(palette): create tile grid + recipes; the sidebar + opens the palette
The palette's empty state now leads with a Create tile grid (shared list in
data/createItems.js) plus a '+ n more' shelf that folds in the less-common
targets and any extension-contributed 'New ...' commands, then a Recipes
group (picking one starts it and opens the recipes console). Create and
recipe entries also score into regular search results.

The sidebar '+' stops carrying its own little dropdown and opens this
palette instead — one door for every new-thing flow, like the prototype.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 02:43:24 -04:00
Juan DenisandClaude Fable 5 3f3ff156f1 feat(ai): dock the assistant into the shell console; drop Prompture branding
The right-side chat drawer now carries the shared console tab strip, so the
assistant reads as the right-docked tab of the same console the bottom
panels belong to (its close moved into the strip). The 'powered by
Prompture' lines are gone from the header and empty state — the empty state
now tells the user what to ask instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 02:43:15 -04:00
Juan DenisandClaude Fable 5 6a8e80d7f1 feat(shell): one tabbed console + styled scope menus (port prototype chrome)
The bottom-edge surfaces (Operations, Alerts, Recipes, Assistant) now share
one console: every panel carries the same four-tab strip (ShellDockTabs) and
a ShellDockContext keeps exactly one open, so switching surfaces is a tab
click instead of hunting separate popovers. Recipes is rebuilt into the
prototype's split layout — step rail left, one step's story right, with a
deep-link action button, 'Done - next step', and Back.

The workspace/server switchers get real themed menus (dot - name - meta -
check) replacing the native <select> popup that ignored the theme, and the
sidebar keeps its full height again: it was shortened by the statusbar
height even though the bar only spans the content column, leaving a dead
30px hole under the user card.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 02:43:06 -04:00
github-actions[bot] a91c07ba20 chore: bump version to 1.9.1 [skip ci] 2026-08-22 05:33:46 +00:00
Juan Denis c0de9fbcac refactor(i18n): consolidate duplicate locale strings into common.* namespace
en.json drops from 8107 to 6624 keys: repeated UI copy (Cancel x95,
Status x67, Refresh x54, ...) now lives under common.actions /
common.labels / common.loading, and extractor-era suffix duplicates
(refresh2, status3) within a component collapse onto one key.
Trailing ... defaults are normalized to the ellipsis character.

Translations are preserved: all 16 locales were re-keyed, carrying
existing per-component translations onto their new common.* keys
(majority vote where sources disagreed), and stale keys were pruned.

Verified: npm run lint (0 errors), node --test (140 pass), vite build.

edit
2026-08-22 01:32:52 -04:00
github-actions[bot] 77dfed6a64 chore: bump version to 1.9.0 [skip ci] 2026-08-22 04:55:39 +00:00
Juan Denis 6eb7e5433d feat: redesign app shell and file manager 2026-08-22 00:41:06 -04:00
Juan Denis 7b7779a6b2 fix(monitoring): restore missing disk-reclaim stylesheet (unbreaks build) 2026-08-21 23:59:46 -04:00
Juan Denis a16561a0fb refactor(ds): fold Drawer/PageTopbar/AppMap static styles into SCSS 2026-08-21 23:54:26 -04:00
Juan Denis 5a297adf97 refactor(ui): move widget/skeleton static inline styles into SCSS 2026-08-21 23:50:42 -04:00
Juan Denis 6ddeb0dad4 refactor(setup): replace wizard inline styles with modifier classes 2026-08-21 23:45:03 -04:00
Juan Denis 9f1aed7943 refactor(settings): replace static inline styles with SCSS classes 2026-08-21 23:43:02 -04:00
Juan Denis ab7505c934 refactor(servers): replace static inline styles with SCSS classes 2026-08-21 23:35:44 -04:00
Juan Denis 58dce6225b fix(a11y): make JS smooth-scrolls honor prefers-reduced-motion 2026-08-21 23:20:11 -04:00
github-actions[bot] 81875f0e77 chore: bump version to 1.8.1 [skip ci] 2026-08-22 03:07:04 +00:00
Juan Denis 515d960614 chore(ratchets): regenerate the boundary baseline, error ceiling and migration inventory
The recipes Phase 0 commit moved all three measured counts without
regenerating their baselines. The new api/recipes.py persistence
crossings are owned and documented in the baseline; the hand-shaped
error census is unchanged by this branch.
2026-08-21 23:05:56 -04:00
Juan Denis 36409d6ddf fix(crypto): keep recipe handoff secrets behind the vault one door
RecipeExecutionService encrypted handoff inputs with a direct
app.utils.crypto import, tripping the service-level crypto ratchet.
SecretService gains upsert_internal_secret — create-or-update without
the human display-name grammar, for machine-named secrets in a
dedicated vault slug — and the recipe service routes through it.
2026-08-21 23:05:48 -04:00
Juan Denis f5023c0613 feat(disk): reclaim space from the panel
Expose disk_reclaim_service behind /api/v1/system/disk/reclaim: a
read-only report and a confirm-gated POST whose keys are re-validated
against a fresh scan server-side (safe candidates only — telemetry
stays CLI-only). ?wait=false runs it as a background job; both paths
are audit-logged.

The curated fix shows up where the problem is reported: a failing
disk.headroom doctor check and an alerting disk tile each offer
'Reclaim space', which previews measured candidates before handing
the run to Operations.
2026-08-21 23:05:40 -04:00
github-actions[bot] 954af86199 chore: bump version to 1.8.0 [skip ci] 2026-08-22 02:06:28 +00:00
Juan Denis d6950cc40f feat: add guided operator walkthroughs 2026-08-21 22:04:09 -04:00
Juan Denis 811cf7dde9 feat: add resumable recipe execution foundation 2026-08-21 21:47:24 -04:00
Juan Denis 5ff4a4e87b Merge pull request #115 from jhd3197/dev
Unify runs and resource pickers, and stop the disk filling up
v1.7.130
2026-08-21 20:49:58 -04:00
Juan Denis 72f0c780dd Merge branch 'main' into dev 2026-08-21 20:30:52 -04:00
github-actions[bot] 4e543dbd86 chore: bump version to 1.7.130 [skip ci] 2026-08-22 00:20:09 +00:00
Juan DenisandClaude Opus 5 924a08c3ff chore(dev): add scripts/preflight.sh -- run what CI checks, locally
Five red CI rounds in one day, none of them a broken feature: a floor measured
on a dev box, a fingerprint baseline left unregenerated after a refactor, a
ceiling that moved with the code, a generated doc gone stale, and a text-grep
guard that matched a docstring. Every one is an AST or text scan over the tree
that needs no shard and no push to run.

preflight.sh runs the test-count ratchet, every backend ratchet/census/guard
test (matched by filename, so a new ratchet is covered the day it lands rather
than the day someone remembers this script), the frontend boundary check, and
the migration-inventory freshness check. About two minutes against a five-minute
push-and-wait.

It resolves node.exe through WSL interop, so the one WSL invocation in the
header comment covers both halves on this dev box. The inventory check compares
against a snapshot of the file rather than against HEAD, so an uncommitted but
correct regeneration is a pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 20:15:15 -04:00
Juan DenisandClaude Opus 5 550dd47585 fix(ratchets): regenerate the boundary baseline and the migration inventory
Two more shards were red on generated artifacts nobody regenerated:

- api_controller_boundary_baseline.json: the attachment round rewrote
  _persist_user_message to build the row before adding it, so the fingerprint
  moved from `db.session.add(AiMessage(...))` to `db.session.add(message)`.
  Same crossing, same category, count unchanged at 509 -- one line.

- docs/MIGRATION_INVENTORY.md: three measured numbers had moved without a
  regeneration -- bare @jwt_required() routes 577 -> 576, and the two frontend
  rows whose totals come from maps inside check-frontend-boundaries.mjs
  (setInterval pollers 10 -> 9, hex colour literals 151 -> 150). All three are
  deterministic AST/constant counts, so these are CI's numbers, not this box's.

The reason nobody caught the inventory locally is the third fix here: the
generator hardcoded `node`, and under WSL the Windows nvm directory is on PATH
but exposes only `node.exe`, so test_migration_inventory.py skipped on the dev
box. Both the generator and the test now resolve $NODE / node / node.exe, and
the test runs instead of skipping.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 20:14:34 -04:00
Juan DenisandClaude Opus 5 1c659824c1 fix(tests): the create_app guard must read code, not prose
The plan-77 G3 guard grepped raw file text for `create_app(`, so it counted
mentions. test_disk_reclaim.py failed CI for a docstring reading "Stand-in for
create_app() -- the disk command only needs a context": that file monkeypatches
the factory away and never boots anything. The same false positive had already
put test_api_error_shape.py into the baseline, for a comment.

Detection is now AST-based -- a real call, direct or attributed. String
literals still count, because test_ai_lazy_import.py boots its probe app from an
embedded script; docstrings and comments never boot anything, and an
unparseable file falls back to the old blunt check rather than passing free.

Baseline drops test_api_error_shape.py (it uses the shared `app` fixture) and
gains nothing. test_boot_detection_reads_code_not_prose proves the scanner
against both false positives and all three true positives, so the next docstring
does not turn CI red. BASELINE_COUNT +1 for it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 20:14:34 -04:00
Juan DenisandClaude Opus 5 009d9c4d7f fix(ai): raise a typed error for a malformed attachment manifest
The attachment round added two hand-shaped `jsonify({'error': str(exc)}), 400`
returns in api/ai.py, which pushed the error-shape census to 1146 against a
ceiling of 1144 and turned shard 2 red. The census policy is not "raise the
ceiling" -- new endpoints raise, and these are new.

AttachmentValidationError now subclasses app.exceptions.ValidationError, so the
global handler owns the 400 body, the `code`, and the X-Request-ID correlation.
It is still a ValueError (ValidationError subclasses one), so every existing
`except ValueError` caller and the pytest.raises assertions in
test_ai_attachments.py are unchanged, and the two try/except blocks in the
routes disappear entirely.

Census back to 1144 = ceiling. Verified: test_ai_attachments, test_ai_assistant,
test_error_shape_ratchet all green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 20:14:34 -04:00
github-actions[bot] eb6be3d863 chore: bump version to 1.7.129 [skip ci] 2026-08-21 23:42:15 +00:00
Juan DenisandClaude Opus 5 2ad6720bd0 fix(ci): make the test-count ratchet count what a clean checkout collects
The floor was --update'd from a dev box again, so CI collected 4516 against
a floor of 4530 and the ratchet went red for a suite that lost nothing.
Same 14 cases as last time (4431 -> 4417): test_builtin_extension_drift.py
parametrises over the on-disk intersection of builtin-extensions/<ext>/backend
and app/plugins/<ext>, and four live copies here are gitignored --
cloud-provision (3), ftp (3), remote-access (5), status (3).

Fixing the number alone would queue up a third occurrence, so the
machine-dependence is closed instead: check_test_count.py now collects with
SERVERKIT_CLEAN_COLLECT=1, and under that flag the drift test pairs only
git-TRACKED live copies. Ordinary runs are untouched and still compare the
gitignored copies on the machine that has them.

Verified with the WSL venv: the ratchet now reports 4518 locally, exactly
CI's 4516 plus the two tests added here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 19:40:42 -04:00
github-actions[bot] 4c10601703 chore: bump version to 1.7.128 [skip ci] 2026-08-21 23:31:53 +00:00
Juan Denis 19a7b59bd1 Merge branch 'dev' of https://github.com/jhd3197/ServerKit into dev 2026-08-21 19:31:35 -04:00
Juan DenisandClaude Opus 5 507a467d98 fix(scss): use the amber token for the AI attachment warning state
check-frontend-boundaries failed on dev: _ai-assistant.scss carried 11
colour literals against a legacy baseline of 10.

The extra one came in with the attachment composer as
`var(--warning, <amber literal>)`. `--warning` is not a defined token
anywhere in the tree, so that declaration always fell through to the
literal -- a hardcoded amber that runtime skins could never recolour,
which is precisely what the boundary check exists to catch. (_doctor.scss
reaches for the same undefined token with a *different* fallback, so the
two rendered slightly different ambers.)

$warning resolves to var(--amber, …), the real token. The adjacent line
already uses $warning-raw, so the variables are in scope; $warning itself
must not be fed to fade() since it expands to a var() rather than a
compile-time colour.

File back to 10 literals, matching the baseline without moving it.
Verified: boundary check, theme-token check, npm run lint and npm run
build all pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 19:30:57 -04:00
Juan DenisandClaude Opus 5 406d7c3ff1 chore(tests): raise the test-count floor to 4530
The ratchet only fails on a DROP, so a floor left un-bumped never
complains -- it just quietly stops protecting anything. At 4417 against
4530 collected, 113 tests could have been deleted with CI still green.

113 new tests since the floor was last set: ~35 from the disk-space work
(test_disk_reclaim.py plus the disk --json case) and the rest from the
branch merged into dev.

Verified trustworthy before committing: `pytest tests --collect-only`
(what backend-ci.yml runs) and the bare `pytest` that check_test_count.py
uses both report 4530 -- backend/dev-data/ errors out of collection
rather than adding to it, so the two agree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 19:26:47 -04:00
github-actions[bot] 63c51a3158 chore: bump version to 1.7.127 [skip ci] 2026-08-21 23:25:49 +00:00
Juan Denis 633efc250b Merge branch 'dev' of https://github.com/jhd3197/ServerKit into dev 2026-08-21 19:25:25 -04:00
Juan DenisandClaude Opus 5 b006f2e4da refactor(disk): route the reclaim sweep through run_checked
The raw subprocess census caught disk_reclaim_service as a 25th call
site against a ceiling of 24. The ceiling only goes down, and this is a
case where the shared door is genuinely the better call rather than a
box to tick.

_run's own `except OSError` turned a missing binary into an empty
result, which is exactly the sbin-PATH failure mode: a unit whose $PATH
omits sbin cannot exec a bare `journalctl`, and this sweep would have
reported "nothing to reclaim" on a host that had plenty to reclaim --
a false fact about the operator's disk rather than a visible error.

run_checked resolves argv[0] the way privileged_cmd does, and separates
"never ran" (returncode None) from "answered no". _run keeps its
(ok, stdout, stderr) shape, so callers and tests are unchanged; a
missing binary still degrades to a zero-sized candidate instead of
aborting the scan, but now the reason reaches stderr.

Census back to 24/24; all six ratchets pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 19:23:29 -04:00
github-actions[bot] 9dd1550ff1 chore: bump version to 1.7.126 [skip ci] 2026-08-21 23:19:17 +00:00
Juan DenisandClaude Opus 5 9e84923ef8 Merge fix/consolidate-error-state into dev
Brings the disk-space work (serverkit disk, telemetry retention, updater
hardening) plus the AI attachment composer, operations run consolidation
and remote-access pickers already on the branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 19:15:42 -04:00
Juan DenisandClaude Opus 5 6d2f71d789 fix(update): stop the updater from being able to fill the disk
A backup retention cap already existed (SERVERKIT_BACKUP_RETENTION,
default 5), yet a box was found holding six snapshots and 0 bytes free.
Three separate defects, each sufficient on its own:

1. cleanup() is the LAST phase of the update, so retention never ran on
   a run that died earlier -- including the run that died BECAUSE the
   disk was full. Retention that only executes on success cannot bound a
   failure loop. backup_current now trims BEFORE writing, which also
   makes peak usage `keep` snapshots rather than `keep + 1`.

2. The preflight required a flat 2 GiB, but the update is about to write
   two full copies of the database. With an 800 MB database a box at
   2.1 GiB free passed the check and then filled mid-update. The
   requirement is now 2 GiB + 2x the database, it trims stale snapshots
   and re-checks before giving up, and the halt message points at
   `serverkit disk`.

3. A count cap is not a disk guarantee: five snapshots of an 800 MB
   database is 8 GB, a third of a 25 GB droplet. The default drops to 3
   and enforce_backup_budget caps backups at a share of the filesystem
   (SERVERKIT_BACKUP_MAX_PERCENT, default 15), dropping oldest-first and
   always keeping at least one restore point -- an update with no way
   back is worse than a full disk.

BACKUP_DIR also becomes SERVERKIT_BACKUP_DIR-overridable so it can agree
with the reclaim service, which scans the same directory.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 19:12:42 -04:00