mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
docs(agents): compact root guidance and preserve task-specific knowledge (#1645)
* docs(agents): compact root guidance and preserve task-specific knowledge * fix(agents): parse guidance navigation with Markdown tokens * fix(agents): validate generic literal repository paths * fix(agents): distinguish code symbols and shortcut images * fix(agents): recognize SCSS filename literals * fix(agents): handle fenced imports and encoded paths * fix(agents): parse prose and rendered HTML anchors * fix(agents): validate rendered HTML navigation * fix(agents): use GitHub-compatible heading slugs * fix(agents): require standalone top-level Claude import * fix(agents): exclude HTML-contained guidance imports * fix(agents): handle image fragments and quoted imports * fix(agents): validate visible HTML and image source sets * fix(agents): recognize package scopes and route source work * fix(agents): parse JSONC and constrain package exemptions * fix(agents): decode link entities and allow package subpaths * fix(agents): route source work and check extensionless files * fix(agents): support package versions and source fragments * fix(agents): accept qualified package prose * fix(agents): retain rendered context for Markdown references * fix(agents): validate visible headings and spaced paths * fix(agents): validate media and hyphenated literal paths * fix(agents): decode full HTML entities and media assets * fix(agents): recognize possessive package mentions * fix(agents): validate extensionless imports and version comparators * fix(agents): retain visible backticks and explicit path punctuation * fix(agents): validate image-map navigation targets * fix(agents): count all Markdown line endings in budgets * fix(agents): delimit package prose at Unicode punctuation * fix(agents): normalize punctuation for extensionless imports * fix(agents): preserve filenames across prose punctuation * fix(agents): validate iframe document references * fix(agents): inspect document suffix before URL fragments * fix(agents): unify Markdown suffix and encoded import guards * fix(agents): handle wildcard versions and alternate documents * fix(agents): validate document formats and trim HTML URLs * fix(agents): cover document families and guidance basenames * fix(agents): require files for media references * fix(agents): preserve block boundaries and validate embeds * fix(agents): normalize internal HTML URL whitespace * fix(agents): reject empty media and ignore URL at-signs * fix(agents): validate srcdoc references and empty srcset * fix(agents): honor HTML bases and preserve adjacent imports * fix(agents): convert base file URLs to native paths * fix(agents): preserve imports after bare URL punctuation * fix(agents): exclude opaque URI prose from import scans * fix(agents): keep import tokens outside URI scheme matches * fix(agents): restrict opaque URI exemptions to parsed links * fix(agents): handle opening prose delimiters * fix(agents): scan nested imports and share document suffixes * fix(agents): reject pathless media and direct file URLs * fix(agents): reject file bases and preserve quoted URL boundaries * fix(agents): distinguish URL quotes and cover guidance variants * fix(agents): validate SVG images and conventional guides * fix(agents): handle declared package names handles and SVG use * fix(agents): normalize closing punctuation on federated handles * fix(agents): normalize Unicode punctuation on handles * fix(agents): normalize possessive federated handles * fix(agents): separate parenthetical prose from handles * fix(agents): exclude www autolinks from import scanning * ci: allow manual CodeQL validation of PR branches * fix(agents): reject nonportable Windows drive links
This commit is contained in:
1 parent
b02d79805b
commit
faad8fd8fd
24 files changed
+4178
-3256
No files matched your search
@@ -1906,3 +1906,44 @@ deletes with follow-up cleanup warnings. The UI does not resurrect a deleted
|
||||
row after a cleanup failure. Downloaded files are not removed. The dialog's
|
||||
confirmation covers deletion of the source and associated favorites, history
|
||||
and playback positions; no deletion happens on merely opening the dialog.
|
||||
|
||||
## Opening playlists from the operating system
|
||||
|
||||
Electron only: a `.m3u`/`.m3u8` path passed
|
||||
on the command line, opened through a file association, or delivered by macOS'
|
||||
`open-file` event is normalized to an absolute path in the main process
|
||||
(`apps/electron-backend/src/app/services/playlist-open-request.ts`) and queued there. The renderer
|
||||
(`apps/web/src/app/services/playlist-open-request.service.ts`) subscribes to the
|
||||
`OPEN_FILE` push **before** calling `announcePlaylistOpenListener`, which is
|
||||
what makes the main process flush. `OPEN_FILE` is the only way out of the
|
||||
queue, and a request stays there until the renderer confirms receipt via
|
||||
`acknowledgePlaylistOpenRequest` — `webContents.send()` returns before the
|
||||
listener runs, and a reload or dead render process keeps the `WebContents`
|
||||
alive, so a successful push is not proof of delivery. Anything unacknowledged
|
||||
is replayed to the next renderer that announces itself. The renderer
|
||||
imports them on a single promise chain so a burst arrives in a deterministic
|
||||
order. `addPlaylist$` in `libs/m3u-state` uses `concatMap` (not `switchMap`)
|
||||
for the same reason: each action carries a different playlist, so a newer add
|
||||
must never cancel an older one's write, EPG fetch and navigation. The import
|
||||
itself reuses the normal file path
|
||||
(`updatePlaylistFromFilePath` → `PlaylistActions.addPlaylist`), so persistence,
|
||||
playlist-scoped EPG, and the navigation to the new playlist all behave exactly
|
||||
like a dialog import.
|
||||
|
||||
The OS-level registration that makes those paths reachable is
|
||||
`fileAssociations` in `electron-builder.json` — one entry per extension, each
|
||||
with its own `mimeType`. Electron Builder derives all three platform
|
||||
registrations from it: macOS `CFBundleDocumentTypes` (which is what makes
|
||||
`open-file` fire from Finder), the NSIS registry entries, and, on Linux, the
|
||||
desktop entry's `MimeType` plus `/usr/share/mime/packages/iptvnator.xml` for
|
||||
deb/rpm/pacman. Two traps: it assigns the derived `MimeType` _after_ spreading
|
||||
`linux.desktop.entry`, so declaring `MimeType` there is silently overwritten and
|
||||
must not be used; and it appends `%U` to `Exec`, so Linux file managers hand
|
||||
over percent-encoded `file://` URIs rather than paths —
|
||||
`createPlaylistOpenRequest` decodes them before the extension check. `%U` is
|
||||
also the _plural_ exec code, so a multi-file selection arrives as one launch
|
||||
with one argument per file; `extractPlaylistOpenRequestsFromArgv` returns all
|
||||
of them and `enqueueAll` queues the batch, because stopping at the first match
|
||||
would silently drop the rest of the selection. Adding an exec code to
|
||||
`linux.executableArgs` would suppress the `%U` but also pass that code to the
|
||||
app as a real argument, so it is not an option.
|
||||
@@ -130,6 +130,22 @@ patched prefilter/matcher wiring and version pin, stress-tests the false-positiv
|
||||
chunk shape, and preserves ordinary and comment-bearing asset and worker
|
||||
`new URL(..., import.meta.url)` matches.
|
||||
|
||||
## Electron Builder signing patch
|
||||
|
||||
`app-builder-lib` 26.15.7 is patched in
|
||||
`patches/app-builder-lib@26.15.7.patch` with the upstream backport
|
||||
electron-userland/electron-builder#10172. For macOS signing,
|
||||
`security set-key-partition-list -k` must receive the temporary keychain's own
|
||||
password rather than the `.p12` import password. macOS runner images since
|
||||
`macos-26-arm64` 20260831 verify that password; the old argument caused
|
||||
`SecKeychainUnlock: The user name or passphrase you entered is not correct`.
|
||||
Keep the patch until electron-builder resolves a fixed app-builder-lib (26.16.1+).
|
||||
Run `pnpm run deps:electron-builder:test` after related dependency updates; it
|
||||
also rejects a mismatch between the patched and installed version.
|
||||
|
||||
Native addon builds additionally require the root `node-gyp` devDependency;
|
||||
see [runtime staging](embedded-mpv-native.md#runtime-staging) before removing it.
|
||||
|
||||
## Placement Decision
|
||||
|
||||
- `apps/` owns runtime applications, development servers, E2E applications,
|
||||
|
||||
@@ -7,6 +7,9 @@ Embedded MPV rendering and native-view bounds behavior remain documented in
|
||||
|
||||
## Current status
|
||||
|
||||
The shared-controls preference checkbox is visible only when HTML5, Video.js
|
||||
or ArtPlayer is selected in Settings → Playback.
|
||||
|
||||
The shared-controls foundation supports four runtime consumers and includes:
|
||||
|
||||
- the `PlayerController` contract, default state, and capability presets;
|
||||
@@ -1533,3 +1536,36 @@ replacement, track-list lifecycle and stable IDs, caption preference and
|
||||
explicit-off behavior, MPEG-TS live/VOD handling and duration projection,
|
||||
volume preservation/authority, stale ArtPlayer `customType` callbacks, and
|
||||
collaborator teardown. Persistent/background player ownership has not landed.
|
||||
|
||||
## Radio and display sleep
|
||||
|
||||
### Radio audio player
|
||||
|
||||
M3U `radio="true"` entries use `AudioPlayerComponent` under
|
||||
`libs/ui/playback/src/lib/audio-player/`. The player always renders inline and
|
||||
uses HTML5 `<audio>` regardless of the configured video player. Radio bypasses
|
||||
`shouldShowInlinePlayer`'s external-player gate and hides the EPG ribbon and panel
|
||||
toggle. The station artwork, blurred logo background and glass controls form the
|
||||
radio layout; title/group scrolling is CSS-only. It supports play/pause, mute,
|
||||
and volume, including the volume keys in 5% steps. Volume shares the video
|
||||
players' `volume` localStorage key. The template, SCSS and TypeScript component
|
||||
live together; routing/integration stays in the M3U player template.
|
||||
|
||||
### Display sleep during playback
|
||||
|
||||
`PlaybackKeepAwakeService` in the web app watches `<video>` using document-level
|
||||
capture listeners because media events do not bubble. Release listeners also
|
||||
attach to the tracked element: Chromium's pause after DOM removal never reaches
|
||||
the document. A playing video holds a display-sleep lock only while the document
|
||||
is visible or that video is in picture-in-picture, which survives minimization.
|
||||
|
||||
Electron uses main-process `powerSaveBlocker` through
|
||||
`window.electron.setPlaybackKeepAwake`. The renderer vote clears on reload,
|
||||
main-frame non-same-document navigation, crash (`render-process-gone`) or
|
||||
destruction; Angular navigation does not itself clear it. The PWA uses Screen
|
||||
Wake Lock. Browser auto-release clears its sentinel; the next media, visibility
|
||||
or PiP synchronization can request another lock. If state changes during a
|
||||
pending request, rejection triggers one queued re-evaluation rather than losing
|
||||
that update. Radio `<audio>` deliberately never blocks display sleep.
|
||||
Embedded MPV owns a separate blocker in `EmbeddedMpvNativeService`, and external
|
||||
MPV/VLC inhibit their own screensaver.
|
||||
@@ -277,3 +277,25 @@ For manual Docker smoke testing, run the Xtream and Stalker mock servers plus a
|
||||
small M3U fixture, then verify in the browser that M3U, Xtream, and Stalker can
|
||||
add sources, play an item, toggle favorites, populate global favorites,
|
||||
populate recently viewed, and appear on the dashboard rails.
|
||||
|
||||
## Service factory and build bases
|
||||
|
||||
`DataService` in `libs/services/src/lib/data.service.ts` is the renderer service
|
||||
contract. `DataFactory()` in `apps/web/src/app/app.config.ts` chooses
|
||||
`ElectronService` for the desktop bridge and `PwaService` for browser HTTP and
|
||||
IndexedDB work. This environment-level selection is not evidence for an
|
||||
individual capability: Xtream data-source selection requires its complete
|
||||
SQLite bridge, and feature visibility follows `RuntimeCapabilitiesService`.
|
||||
The same workspace route tree is used in both runtimes.
|
||||
|
||||
Desktop relational data uses the canonical schema/connection in
|
||||
`libs/shared/database`; the SQLite path is `~/.iptvnator/databases/iptvnator.db`.
|
||||
Desktop Chromium settings/storage still exist alongside SQLite. PWA data uses
|
||||
browser IndexedDB (with browser quotas); its structure is not the SQL schema.
|
||||
Browser-selected file uploads remain possible even though native filesystem
|
||||
access is Electron-only.
|
||||
|
||||
Web development and PWA use `baseHref="/"`; packaged Electron frontend uses
|
||||
`baseHref="./"` so file URLs resolve. In `apps/web/project.json`, `production`
|
||||
is the Electron frontend build, `pwa` is the web build, and `development` uses
|
||||
the index base. Do not ship the Electron frontend build as a PWA deployment.
|
||||
@@ -11,6 +11,16 @@ pnpm nx show projects --withTarget lint
|
||||
pnpm nx show projects --withTarget e2e
|
||||
```
|
||||
|
||||
## Manual CI Runs
|
||||
|
||||
When a PR event does not start checks for the current head, dispatch CI and E2E
|
||||
with `gh workflow run ci.yml --ref <branch>` and
|
||||
`gh workflow run e2e-tests.yaml --ref <branch>`. CodeQL also supports
|
||||
`gh workflow run codeql-analysis.yml --ref <branch>`; this analyzes the selected
|
||||
branch commit instead of the PR merge commit. Verify each run's head SHA before
|
||||
using its result as evidence. Docker validation can use
|
||||
`gh workflow run docker.yml --ref <branch> -f push=false`.
|
||||
|
||||
## Unit And Type Checks
|
||||
|
||||
| Area | Command |
|
||||
@@ -152,3 +162,31 @@ are gated by:
|
||||
```bash
|
||||
IPTVNATOR_TRACE_PLAYER=1 pnpm run serve:backend
|
||||
```
|
||||
|
||||
## Test impact and completion
|
||||
|
||||
Before finishing a feature, bug fix, data-flow or UI workflow change, identify
|
||||
the affected projects and choose unit, integration, E2E, build, lint and manual
|
||||
checks. Bug fixes normally include regression coverage that fails before the
|
||||
fix. If automation is impractical, explain why and report the strongest manual
|
||||
validation. Update fixtures, mocks, routes and E2E flows when behavior changes.
|
||||
Prefer extending the closest existing suite to introducing a parallel suite.
|
||||
|
||||
Run targeted unit checks first, then affected E2E for workflows, routing,
|
||||
persistence, playback, portals, settings or import flows. Electron IPC, SQLite,
|
||||
packaged runtime, external players, native files and Electron-only routes require
|
||||
Electron E2E where available, otherwise CDP/manual verification using the
|
||||
[debugging guide](../development/electron-debugging.md). Prefer atomized E2E
|
||||
targets before broad suites. Final reports name tests changed, commands/results,
|
||||
and skipped validation with reasons. Docs-only changes need Markdown validation,
|
||||
not app unit/E2E. Tooling validation still requires its own focused tests.
|
||||
|
||||
## Agent guidance checks
|
||||
|
||||
`pnpm run agents:validate` checks root instruction budgets/imports and guidance
|
||||
navigation links/anchors. `pnpm run skills:validate` checks skill frontmatter,
|
||||
length, paths and release mirrors. Both tooling suites run through
|
||||
`pnpm nx test repository-skills`; syntax checks use
|
||||
`pnpm nx lint repository-skills`. The CI guidance check runs regardless of the
|
||||
Nx affected set. Semantic preservation of moved contracts is a review task;
|
||||
link validation alone cannot prove it.
|
||||
@@ -327,3 +327,13 @@ Intentionally out of scope:
|
||||
2. Freeform widget grid with collision management.
|
||||
3. External data rails such as RSS, sports, or news adapters.
|
||||
4. Per-user A/B variants of rail ordering.
|
||||
|
||||
## Source subscription expiry
|
||||
|
||||
Source cards show a passive subscription-expiry chip: amber within seven days,
|
||||
error-toned once expired. Account details stay behind the Account info menu.
|
||||
`DashboardSourceExpiryService` in `libs/workspace/dashboard/data-access` reads
|
||||
Xtream expiry from cached `PortalStatusService.checkPortalStatusDetails()`
|
||||
(`exp_date`). Stalker uses the persisted `stalkerAccountInfo` snapshot from the
|
||||
playlist payload, not the metadata row; each source therefore needs one memoized
|
||||
full-playlist read. The chip is not a separate account-refresh request.
|
||||
@@ -373,3 +373,31 @@ It reuses the canonical timeshift resolver and original timestamps, preserves
|
||||
playback headers and does not change playback. See
|
||||
[Download Manager](download-manager.md#xtream-archive-downloads) for identity,
|
||||
restart, expiry and transport-completion limits.
|
||||
|
||||
## Store composition and catalog windowing
|
||||
|
||||
`XtreamStore` is the public facade built with `signalStore()`, composing
|
||||
`signalStoreFeature()` features for portal, content, selection, search, EPG,
|
||||
player, favorites, recent and playback positions. Most features live under
|
||||
`libs/portal/xtream/data-access/src/lib/stores/features/`; favorites and recent
|
||||
items live directly under the data-access library’s `src/lib/`.
|
||||
Routed components consume that facade; features delegate persistence/networking
|
||||
to `IXtreamDataSource`, selected through `provideXtreamDataSource()`. Complete
|
||||
SQLite capability uses database-first cache reads and API fill; the PWA source
|
||||
uses API requests and session memory. This does not move screen orchestration
|
||||
into shared utility projects.
|
||||
|
||||
Catalog lazy loading: catalog grids scroll infinitely instead of paging.
|
||||
`withSelection` keeps a `visibleCount` render window over the in-memory
|
||||
catalog plus bounded per-selection scroll snapshots for detail/tab
|
||||
round-trips; the shared `InfiniteScrollDirective`
|
||||
(`libs/portal/shared/ui`) measures container overflow to auto-fill tall
|
||||
viewports (terminating on lack of container growth, not on a load count)
|
||||
and fires `loadMore` near the bottom. The search layout routes its results
|
||||
container through the same directive (`nearEnd*` inputs). Stalker feeds the
|
||||
same contract from server-paged appends: portal pages accumulate into one
|
||||
deduplicated list, `hasMoreContent` derives from accumulated length vs
|
||||
`total_items`, a failed append keeps loaded pages and offers a tail retry,
|
||||
and the facade maps page 0 to the skeleton and later pages to the tail
|
||||
spinner. These catalog/search surfaces use incremental loading instead of
|
||||
page buttons.
|
||||
Reference in new issue
Block a user