Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions plugins/appos-dev/compiled/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
"schema": 1,
"artifacts": {
"cli-chat-system-prompt.md": "0ace5e39d569fac84ca22e244bfb5dae8242b14e059395894f16f712b1ecc170",
"plugin-factory-context.md": "229f7fc7d15a6650f0923cf33d88e0712ecbb20a184df24e22d26a2c34783720"
"plugin-factory-context.md": "389a4fc99cdc0fee665ac63bc1600332865b6f3fd7ff5314bd18a54065bf5bec"
},
"sources": {
"SKILL.md": "f4868a887ab7726ca8c6463b90953a1efb82712fb1a3df5e68888f9b43644cd6",
"reference/extension-api.md": "b37b24cd2a5e02345b361ee08aea29a885084ebfb4a8a73358036a91572c49e8",
"reference/patterns.md": "93fc7e840176ab625fe848fb6df92f1c98301b5e13811906696eca3be91822f9",
"reference/plugin-api/index.d.ts": "7299f52226d577aa8ad6160357a8dee2e02f90bb19a18f93ec31d605f5756b27",
"reference/patterns.md": "15be968192b19bbd74735a03571322df1a7c4fece579c6d2b3105eabb270f40a",
"reference/plugin-api/index.d.ts": "cbdd7a4aa96001d3fe664427ffc30039ce09ba80dca2eee32960c5c925c4d8d4",
"reference/plugin-api/core.d.ts": "3e951ef56e6148879fbe92d592399711f4bad5556f1549233ec3d32d0d9c49f9",
"reference/plugin-api/views.d.ts": "323f8570fe1c0e6140b5ee1f46cf79f368dc4d920e4b14544e5bf5753ae05f1e",
"reference/plugin-api/namespaces.d.ts": "467e6374fced48f027c22e9d01fe6daa68839b2f9881726725b901c66ccc8b1f",
Expand Down
34 changes: 17 additions & 17 deletions plugins/appos-dev/compiled/plugin-factory-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -2849,8 +2849,8 @@ void activate;

**File**: `src/services/validate.ts`

AppOS hosts 1.1.0+ inject a native `URL` global — a Foundation-bridged
implementation (macOS `URL(string:)`, RFC 3986), NOT a WHATWG polyfill.
AppOS hosts 1.1.0+ inject a native `URL` global — Foundation-bridged
(macOS `URL(string:)`, RFC 3986), NOT a WHATWG polyfill.
Guard EVERY use, exactly like the timer guard in §8: older hosts never had
it, users can switch it off (`appos.jsc.urlGlobal.disabled`), and menu-bar
contexts do not carry it in v1 — `minHostVersion` removes only the
Expand All @@ -2862,9 +2862,8 @@ const ALLOWED_PROTOCOLS = new Set(['http:', 'https:']);
function isValidMediaUrl(raw: string): boolean {
if (typeof URL !== 'function') {
// Older host / kill switch / menu-bar context: URL is absent.
// Decide the fallback per feature — fail CLOSED for
// security-shaped checks like this one, or hand-parse when the
// feature must still work without URL.
// Fail CLOSED for security-shaped checks like this one, or
// hand-parse when the feature must work without URL.
return false;
}
// canParse never throws (unlike the constructor), so probe first.
Expand All @@ -2878,16 +2877,17 @@ void isValidMediaUrl;

**Key points:**
- `typeof URL === 'function'` before EVERY use — same contract as the
timer guard (§8); the §18 ambient file's `| undefined` typing turns an
timer guard (§8); the §18 ambient `| undefined` typing turns an
unguarded `new URL(...)` into a compile error, not a runtime surprise.
- **Parse coherence**: `u.hostname` is lowercased and, for the same input,
is the exact host string that enters the AppOS host's own security
normalizers (permission validation, initial-hop network checks) —
plugin-side URL validation parses identically to host-side enforcement.
- **Parse coherence**: `u.hostname` is lowercased and is the exact host
string entering the host's security normalizers — plugin-side URL
validation parses identically to host-side enforcement.
- `URL.canParse(input, base?)` returns a boolean and NEVER throws;
`new URL(...)` throws a real `TypeError`
(`e instanceof TypeError === true`) on scheme-less or unparseable input,
and validates a supplied `base` first.
(`e instanceof TypeError === true`) on unparseable input, and on
scheme-less/scheme-relative input lacking a valid absolute `base`
(`new URL('/api', 'https://x.test')` resolves); a bad `base` throws
first.
- Instances are immutable (readonly accessors; assignment is a
sloppy-mode no-op). `String(u)`, template literals, and
`JSON.stringify(u)` all yield `u.href`.
Expand All @@ -2896,11 +2896,11 @@ void isValidMediaUrl;
malformed percent sequences, so wrap it in try/catch).
- Pinned Foundation-vs-WHATWG divergences (intended — do not "fix"):
default ports are RETAINED (`https://x:443/` keeps port `"443"`), an
empty path stays `""` (not `"/"`), IPv6 hostnames come WITHOUT brackets
while `host`/`origin` re-bracket them (`https://[::1]:8443/x`
hostname `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`),
and pre-encoded query values double-encode on an href round-trip
(`%3A` → `%253A`).
empty path stays `""` (not `"/"`), and IPv6 hostnames come WITHOUT
brackets while `host`/`origin` re-bracket them (`https://[::1]:8443/x`
hostname `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`).
(The `%3A` → `%253A` double-encode is `URLComponents.queryItems`-only;
`href` round-trips preserve pre-encoded query values verbatim.)

## Further reading

Expand Down
34 changes: 17 additions & 17 deletions plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -1372,8 +1372,8 @@ void activate;

**File**: `src/services/validate.ts`

AppOS hosts 1.1.0+ inject a native `URL` global — a Foundation-bridged
implementation (macOS `URL(string:)`, RFC 3986), NOT a WHATWG polyfill.
AppOS hosts 1.1.0+ inject a native `URL` global — Foundation-bridged
(macOS `URL(string:)`, RFC 3986), NOT a WHATWG polyfill.
Guard EVERY use, exactly like the timer guard in §8: older hosts never had
it, users can switch it off (`appos.jsc.urlGlobal.disabled`), and menu-bar
contexts do not carry it in v1 — `minHostVersion` removes only the
Expand All @@ -1385,9 +1385,8 @@ const ALLOWED_PROTOCOLS = new Set(['http:', 'https:']);
function isValidMediaUrl(raw: string): boolean {
if (typeof URL !== 'function') {
// Older host / kill switch / menu-bar context: URL is absent.
// Decide the fallback per feature — fail CLOSED for
// security-shaped checks like this one, or hand-parse when the
// feature must still work without URL.
// Fail CLOSED for security-shaped checks like this one, or
// hand-parse when the feature must work without URL.
return false;
}
// canParse never throws (unlike the constructor), so probe first.
Expand All @@ -1401,16 +1400,17 @@ void isValidMediaUrl;

**Key points:**
- `typeof URL === 'function'` before EVERY use — same contract as the
timer guard (§8); the §18 ambient file's `| undefined` typing turns an
timer guard (§8); the §18 ambient `| undefined` typing turns an
unguarded `new URL(...)` into a compile error, not a runtime surprise.
- **Parse coherence**: `u.hostname` is lowercased and, for the same input,
is the exact host string that enters the AppOS host's own security
normalizers (permission validation, initial-hop network checks) —
plugin-side URL validation parses identically to host-side enforcement.
- **Parse coherence**: `u.hostname` is lowercased and is the exact host
string entering the host's security normalizers — plugin-side URL
validation parses identically to host-side enforcement.
- `URL.canParse(input, base?)` returns a boolean and NEVER throws;
`new URL(...)` throws a real `TypeError`
(`e instanceof TypeError === true`) on scheme-less or unparseable input,
and validates a supplied `base` first.
(`e instanceof TypeError === true`) on unparseable input, and on
scheme-less/scheme-relative input lacking a valid absolute `base`
(`new URL('/api', 'https://x.test')` resolves); a bad `base` throws
first.
- Instances are immutable (readonly accessors; assignment is a
sloppy-mode no-op). `String(u)`, template literals, and
`JSON.stringify(u)` all yield `u.href`.
Expand All @@ -1419,11 +1419,11 @@ void isValidMediaUrl;
malformed percent sequences, so wrap it in try/catch).
- Pinned Foundation-vs-WHATWG divergences (intended — do not "fix"):
default ports are RETAINED (`https://x:443/` keeps port `"443"`), an
empty path stays `""` (not `"/"`), IPv6 hostnames come WITHOUT brackets
while `host`/`origin` re-bracket them (`https://[::1]:8443/x`
hostname `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`),
and pre-encoded query values double-encode on an href round-trip
(`%3A` → `%253A`).
empty path stays `""` (not `"/"`), and IPv6 hostnames come WITHOUT
brackets while `host`/`origin` re-bracket them (`https://[::1]:8443/x`
hostname `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`).
(The `%3A` → `%253A` double-encode is `URLComponents.queryItems`-only;
`href` round-trips preserve pre-encoded query values verbatim.)

## Further reading

Expand Down
Loading