dbede032ebefdd36105f66f53b03516734b518fc
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
30e8055536 |
[pending-judge] feat(DC-165 rev5): product/site uniformity — fleet gate proven at composition root, single-source capabilities manifest
Site-vs-product audit (2026-10-09, owner decisions: "advertise as Premium"
and "It should be LLM readable") reconciles the entitlement triangle:
marketing copy <-> PREMIUM_FEATURES <-> license-server grant list.
(Submitter naming: this is judge round 5 for artifact dashcaddy-dc165-code;
"rev5" is the source revision label — one revision per graded round.)
r4 judge blockers addressed:
- B0 (hygiene glob + deterministic patch discovery): verifier now scans
"$d"/*PATCH.diff and *.md/*.sh GLOBS instead of enumerated name lists —
the judge worktree's 4_PATCH.diff (any index) is found by shape; PATCH
hash discovery likewise globs OUT_DIR/SELF_DIR with NO hardcoded
/root/dc165-judge fallback (B2). Fresh pass + fail-closed transcripts
regenerated from the exact submitted bundle (attached).
- B1 (derivation honesty): openapi.yaml + capabilities.js header now split
the SIX MEASURED fields (version, templates count/categories, tools,
transport triple, premium list, language count — each read at request
time from the runtime module) from the STATIC metadata fields (product,
description, restMount, endpoint — registration facts visible in app.js,
labeled as such). The no-drift claim attaches only to the measured set.
- B2: external hardcoded fallbacks removed (above).
- P0: revision labels synchronized (this paragraph).
- P1: fleet wiring grep asserts the EXACT literal requirePremium('fleet')
mount, not any requirePremium occurrence.
Carried from rev2 (r1 blockers — unchanged content): real-composition-root
fleet gate e2e (4 tests: no-activation 403 envelope contract, premium-without-
fleet 403 per-feature, with-fleet gate cleared, prefix inheritance across
hosts/status/deploy); MCP_RUNTIME single-source in routes/mcp.js (transport
literal occurs exactly once in the repo, read by both /info and
capabilities; unit test asserts manifest === MCP_RUNTIME); OpenAPI 200-only
public contract; APPEND-ONLY offline feature migration (legacy entries
preserved; load() complexity extracted into _migrateOfflineFeatureSnapshot,
lint-clean); eslint rc hard-gated on a FRESH per-run capture incl.
middleware.js.
Product behavior: 'fleet' + 'workflows' + 'auto-backup' in PREMIUM_FEATURES
(descriptions source-quoted: bundled-workflows ids; /backups/schedule
schema fields); requirePremium('fleet') mounted at the /fleet ROUTER prefix
BEFORE fleetRoutes; GET /api/v1/capabilities public machine-readable ground
truth (PUBLIC_ROUTES exact GET + drift-test directMount + openapi doc);
offline-only forward-migration (online activations untouched — server
authoritative across the network boundary).
Diff: 9 files vs
|
||
|
|
e80e3273b7 |
[pending-judge] feat(DC-163): AI assistant that works — LLM intent engine + fixed chat panel
The floating assistant was broken end-to-end; Sami said "Do it that works".
Three user-visible bugs fixed + the promised LLM delegation implemented:
FRONTEND (status/js/ai-chat.js — rewritten):
- Response parsing: old code read data.data; the API returns the FLAT ok()
envelope — EVERY reply rendered "Sorry, something went wrong". Now reads
the real shape (contract asserted by route test).
- Suggestion chips: onclick="...send('"Deploy Plex"')" — nested quotes,
invalid JS, dead buttons (shipped like this). Now data-driven buttons with
addEventListener.
- Deploy button: called window.openAppSelector which NEVER existed anywhere
in the tree (grep-verified). Now opens the REAL deploy modal via new
window.openDeployConfigFor(templateId) exported by app-selector.js —
resolves against the live API template cache, reuses showDeployConfig
(same path a manual catalog click takes). Widgets route to the grid.
- Conversation history (last 6 turns) now rides along per request, engine
badge in header, ⚙ settings sub-panel (baseUrl/model/API key + Test +
Remove), all server text via textContent (no HTML injection), CSP-safe
(no inline handlers).
BACKEND (routes/ai-intent.js):
- TWO engines, one contract. LLM classifier (OpenAI-compatible chat
completions) with system prompt embedding the LIVE 78-app catalog + the
six wizard categories; regex patterns kept as the zero-config default and
the automatic failover (HTTP error, timeout via AbortController,
unparseable output -> pattern answers; response carries engine +
llmError so the UI can say which served — no silent degradation).
- Closed-vocabulary schema validation: intent MUST be in the known set else
'unknown'; appId MUST exist in APP_TEMPLATES else nulled (hallucinated
ids cannot leak into deploy plans); categories filtered to the wizard's
real keys; reply stripped of control chars + bounded to 600; history
role-filtered (only user/assistant pass — client-injected system turns
dropped) + capped; input capped to 1000 chars.
- enrich() rebuilds the response contract per intent; pattern-canned
response is dropped when the LLM rerouted the intent (no stale shape);
deployPlan body.port now fills from the template's defaultPort (was
hardcoded null); deployPlan shape asserted against wizard usage.
- Key storage: PUT /ai/settings stores {baseUrl,model,apiKey} in the
ENCRYPTED credential store (key 'ai:llm') via ctx.credentialManager —
NOT config.json (GET /config echoes the raw file to the browser; that
route's shape was verified before this decision). Blank apiKey on PUT
keeps the stored one. GET /ai/settings reports configured/source/model/
hasApiKey — the key value NEVER crosses the wire (asserted). Env
fallback AI_LLM_BASE_URL/AI_LLM_API_KEY/AI_LLM_MODEL + legacy
LLM_PROXY_URL for headless installs. POST /ai/settings/test = one-shot
real classify probe returning ok/sample or ok:false/reason (never
throws). DELETE clears.
- GET /ai/capabilities now reports engine + llm status (pattern was honest
marketing before; now it can be true).
MOUNT (src/app.js): aiIntentRoutes receives siteConfig, log, fetchImpl
(ctx.fetchT — test-injectable) and credentialManager.
Docs: OpenAPI +4 AI path entries (intent, capabilities, settings, settings/test); CHANGELOG entry; dist bundle rebuilt
(openDeployConfigFor present in features.js; SW cache c62511c40d).
Tests: 20 NEW in __tests__/routes/ai-intent-engine.test.js (engine
selection w/ and w/o store, off-catalog phrasing via mock LLM,
hallucinated-id nulling, illegal intent coercion, HTTP-500 failover,
AbortError timeout failover, markdown-fence repair, reply sanitization,
history cap+role filter, env config path, intent-disagreement rebuild w/
real jellyfin port 8096, flat envelope contract, 400s, 1000-char cap,
settings GET/PUT/DELETE/test incl. key-never-echoed assertions,
capabilities engine reporting) + the 18 original pattern tests unchanged +
composition-root e2e 8 pass. Full suite: 3643 passed; only the pre-existing
pdf-parse billing family red (6 failed in documented band [5,7], patch
touches no billing file).
|
||
|
|
c9015b59ad |
[pending-judge] feat(DC-162 rev2): "Connect your AI" — spec Streamable HTTP MCP + one-click keys
Judge r1 (grade D) blockers, each fixed and tested:
1. TRANSPORT: custom POST-only JSON-RPC → MCP 2025-03-10 Streamable HTTP
(spec-canonical; replaced HTTP+SSE). POST answers application/json for
requests; valid notifications -> 202 empty; malformed notifications ->
no reply (204); batching removed in this revision -> arrays rejected
-32600. GET (server->client stream) and DELETE (session termination)
answer 405 + Allow: POST — the spec's explicit allowance for stateless
request/response servers; documented in /info + modal + OpenAPI.
Origin header validated when present (DNS-rebinding MUST); Accept
negotiation (json required, else 406); MCP-Protocol-Version header
checked when sent. Clients needing server-initiated streams use the
stdio bridge (unchanged, shares mcp-core).
2. CREDENTIAL TYPE PRESERVATION: routes/mcp.js now forwards the SAME
scheme the caller authenticated with (req.auth.type from
middleware.js:549-586): apikey -> x-api-key, jwt -> Authorization
Bearer (NOT dk_-coerced-x-api-key as r1 did). mcp-core createToolHandler
accepts explicit headers. Tests assert BOTH shapes downstream
(apikey carries x-api-key & no Authorization; jwt carries Bearer & no
x-api-key; zero downstream calls for session denial).
3. JSON-RPC VALIDATION: validateJsonRpc — jsonrpc:'2.0', non-empty string
method, params object-or-omitted, id string|number|null. Invalid
Request -32600 (empty body, empty array, batch); tools/call without
string params.name -> -32602; unknown method -> -32601; error envelopes
carry id null when unpairable. Transport primitives rejected by the
app-wide strict JSON parser (400; asserted).
4. REPRODUCIBILITY: status/dist/features.js + sw.js regenerated and
committed IN THE PATCH (repo convention: DC-130/131 committed bundle
rebuilds). Verifier greps the built bundle for aiconn- (23),
mcp/connections (1), httpConfig (2) so a clean `git am` checkout serves
the real frontend.
Judge r1 polish, all applied:
- verifier accepts 0_PATCH.diff / PATCH.diff naming (indexed artifact);
- connections list filtered server-side to "AI connection (...)" keys
(new GET /mcp/connections, session-only; modal switched to it);
- URL-encoded tool path params (serviceId, containerId, action,
templateId, category, zone) in mcp-core.
Config shape: POST /mcp/config (session-only; apikey 403) returns the
standard Streamable-HTTP card {url, transport: streamable-http, headers:
{x-api-key}, mcpProtocolVersion} + per-client note (ChatGPT note states
the public-https requirement honestly; no fabricated connector claims).
Tests: 57 green (34 route incl. auth matrix/type-preservation/transport
rules/JSON-RPC errors + 23 core). Composition-root e2e (8) boots the real
createApp with the mount. eslint 0 errors. Full suite: only the
pre-existing pdf-parse billing family red (unchanged since base
|
||
|
|
74e21c1edc |
[pending-judge] feat(DC-161): calendar widget + Radicale auto-wiring
- Top-bar calendar widget (status/js/calendar-widget.js): next-appointment
display, settings modal with CalDAV/ICS source management and a
Test-connection probe. Follows the weather-widget pattern.
- Backend routes/calendar.js: sources CRUD (secrets in credential manager,
never in responses), aggregated events across sources with per-source
error isolation, Radicale provision endpoint, CalDAV discover probe.
- src/calendar/ics-parser.js: dependency-free RFC 5545 parser with bounded
RRULE expansion (DAILY/WEEKLY-BYDAY/MONTHLY/YEARLY, COUNT/UNTIL/INTERVAL,
EXDATE consumes COUNT, RECURRENCE-ID overrides), 500-event cap.
- src/calendar/caldav-client.js: CalDAV REPORT time-range queries over
node:https (no new deps), HTTPS-enforced off localhost, 5MiB response cap.
- src/calendar/radicale-provisioner.js: zero-config auto-wiring - generates
a 24-char password, writes Radicale htpasswd config (pure-Node APR1 hash
verified byte-for-byte against openssl passwd -apr1 vectors), stores
credentials, registers the source. Deploy hook in routes/apps/deploy.js
wires any Radicale deployed via the App Selector automatically.
- Radicale app template (tomsquest/docker-radicale) in the catalog.
- Tests: 32 new (parser unit, provisioner unit incl. openssl vectors,
route tests). Full suite 3552 passed; only pre-existing pdf-parse
billing/invoice failures remain (proven red at base
|
||
|
|
503de258b8 |
[grade=pending] QA sprint: commit 103 at-risk files from multi-agent sprint work
Committed by Hermes autonomous QA sprint 2026-08-13. These files were modified during the Aug 12 sprint but never committed. |
||
|
|
d36705bd90 |
feat: 1.5.0 prep — API v1 cutover, LICENSE, CHANGELOG, CI
- Remove legacy /api/ mount; all routes now under /api/v1/ only - Update path matchers (CSRF excludes, public routes, audit log, rate limits) - Move standalone routes (/api/network/ips, /api/docs, /api/docs/spec) to v1 - Update openapi.yaml (110 paths), CA pages, and 4 lingering frontend files - Add LICENSE (proprietary EULA), CHANGELOG.md (Keep a Changelog format) - Add .gitea/workflows/ci.yml (test+lint and security audit jobs) - Fix 9 pre-existing no-empty lint errors so CI starts green - Drop ad-hoc scratch reports and *.bak files from repo root All 739 jest tests pass. Lint is clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
f61e85d9a7 |
Initial commit: DashCaddy v1.0
Full codebase including API server (32 modules + routes), dashboard frontend, DashCA certificate distribution, installer script, and deployment skills. |