@mohamedatia/fly-design-system 2.12.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/scss/_tokens.scss CHANGED
@@ -1,115 +1,115 @@
1
- // ─── visionOS System Colors & Design Tokens ─────────────────────────────────
2
- :root {
3
- --system-red: #FF453A;
4
- --system-orange: #FF9F0A;
5
- --system-yellow: #FFD60A;
6
- --system-green: #32D74B;
7
- --system-mint: #66D4CF;
8
- --system-teal: #6AC4DC;
9
- --system-cyan: #5AC8F5;
10
- --system-blue: #0A84FF;
11
- --system-indigo: #5E5CE6;
12
- --system-purple: #BF5AF2;
13
- --system-pink: #FF375F;
14
- --system-brown: #AC8E68;
15
- --system-gray: #98989D;
16
-
17
- // ── Semantic Status Colors ──
18
- --status-success: var(--system-green);
19
- --status-warning: var(--system-orange);
20
- --status-error: var(--system-red);
21
- --status-info: var(--system-blue);
22
- --status-pending: var(--system-yellow);
23
-
24
- // ── visionOS Typography ──
25
- --font-family: 'SF Pro Display', 'SF Pro', 'Inter', -apple-system, blinkmacsystemfont, 'Segoe UI', sans-serif;
26
- --font-xl-title1: 700 48px/56px var(--font-family);
27
- --font-xl-title2: 700 38px/46px var(--font-family);
28
- --font-large-title: 700 29px/38px var(--font-family);
29
- --font-title1: 700 24px/32px var(--font-family);
30
- --font-title2: 700 22px/28px var(--font-family);
31
- --font-title3: 700 19px/24px var(--font-family);
32
- --font-headline: 700 17px/22px var(--font-family);
33
- --font-body: 510 17px/22px var(--font-family);
34
- --font-callout: 590 15px/20px var(--font-family);
35
- --font-subheadline: 400 15px/20px var(--font-family);
36
- --font-footnote: 510 13px/18px var(--font-family);
37
- --font-caption1: 510 12px/16px var(--font-family);
38
- --font-caption2: 510 12px/16px var(--font-family);
39
-
40
- // ── visionOS Label Colors ──
41
- --label-primary: rgb(255 255 255 / 96%);
42
- --label-secondary: rgb(255 255 255 / 56%);
43
- --label-tertiary: rgb(255 255 255 / 36%);
44
-
45
- // ── visionOS Materials ──
46
- --material-glass: rgb(128 128 128 / 30%);
47
- --material-glass-blur: 50px;
48
- --material-glass-stroke: rgb(255 255 255 / 40%);
49
- --material-glass-specular: inset 0px -0.5px 1px rgb(255 255 255 / 30%),
50
- inset 0px -0.5px 1px rgb(255 255 255 / 25%),
51
- inset 1px 1.5px 4px rgb(0 0 0 / 8%),
52
- inset 1px 1.5px 4px rgb(0 0 0 / 10%);
53
- --material-recessed-bg: linear-gradient(rgb(208 208 208 / 50%), rgb(208 208 208 / 50%)),
54
- linear-gradient(rgb(0 0 0 / 10%), rgb(0 0 0 / 10%));
55
- --material-recessed-shadow: inset 1px 1.5px 4px rgb(0 0 0 / 10%),
56
- inset 1px 1.5px 4px rgb(0 0 0 / 8%),
57
- inset 0px -0.5px 1px rgb(255 255 255 / 25%),
58
- inset 0px -0.5px 1px rgb(255 255 255 / 30%);
59
- --material-thin: rgb(255 255 255 / 6%);
60
- --material-regular: rgb(255 255 255 / 12%);
61
- --material-thick: rgb(255 255 255 / 20%);
62
- --control-idle: rgb(255 255 255 / 6%);
63
- --control-hover: rgb(255 255 255 / 12%);
64
- --control-selected: rgb(255 255 255 / 100%);
65
- --control-disabled: rgb(255 255 255 / 4%);
66
- --separator: rgb(255 255 255 / 12%);
67
- --blur-shadow-small: 0 2px 4px rgb(0 0 0 / 10%);
68
-
69
- // ── visionOS Button Tokens ──
70
- --btn-font-weight: 590;
71
- --btn-symbol-font-weight: 510;
72
- --btn-radius-capsule: 500px;
73
- --btn-radius-rect-lg: 16px;
74
- --btn-radius-rect-sm: 8px;
75
- --btn-sm-height: 32px;
76
- --btn-sm-padding: 0 12px;
77
- --btn-sm-font-size: 15px;
78
- --btn-sm-line-height: 20px;
79
- --btn-sm-symbol-size: 17px;
80
- --btn-sm-gap: 2px;
81
- --btn-reg-height: 44px;
82
- --btn-reg-padding: 0 20px;
83
- --btn-reg-font-size: 17px;
84
- --btn-reg-line-height: 22px;
85
- --btn-reg-symbol-size: 19px;
86
- --btn-reg-gap: 6px;
87
- --btn-lg-height: 52px;
88
- --btn-lg-padding: 0 25px;
89
- --btn-lg-font-size: 19px;
90
- --btn-lg-line-height: 24px;
91
- --btn-lg-symbol-size: 22px;
92
- --btn-lg-gap: 6px;
93
- --btn-symbol-mini: 28px;
94
- --btn-symbol-mini-font: 13px;
95
- --btn-symbol-sm: 36px;
96
- --btn-symbol-sm-font: 15px;
97
- --btn-symbol-reg: 44px;
98
- --btn-symbol-reg-font: 19px;
99
- --btn-symbol-lg: 52px;
100
- --btn-symbol-lg-font: 22px;
101
- --btn-symbol-xl: 60px;
102
- --btn-symbol-xl-font: 26px;
103
- --btn-platter-lighten: rgb(255 255 255 / 6%);
104
- --btn-platter-dodge: rgb(94 94 94 / 18%);
105
- --btn-hover-grad-white: rgb(255 255 255 / 7%);
106
- --btn-hover-grad-gray: rgb(94 94 94 / 14%);
107
- --btn-disabled-lighten: rgb(255 255 255 / 4%);
108
- --btn-disabled-dodge: rgb(94 94 94 / 7%);
109
- --btn-disabled-text: rgb(112 112 112 / 50%);
110
- --btn-selected-bg: rgb(255 255 255 / 96%);
111
- --btn-selected-text: #000;
112
- --link-color: #3CD3FE;
113
- --link-height: 26px;
114
- --link-font-size: 13px;
115
- }
1
+ // ─── visionOS System Colors & Design Tokens ─────────────────────────────────
2
+ :root {
3
+ --system-red: #FF453A;
4
+ --system-orange: #FF9F0A;
5
+ --system-yellow: #FFD60A;
6
+ --system-green: #32D74B;
7
+ --system-mint: #66D4CF;
8
+ --system-teal: #6AC4DC;
9
+ --system-cyan: #5AC8F5;
10
+ --system-blue: #0A84FF;
11
+ --system-indigo: #5E5CE6;
12
+ --system-purple: #BF5AF2;
13
+ --system-pink: #FF375F;
14
+ --system-brown: #AC8E68;
15
+ --system-gray: #98989D;
16
+
17
+ // ── Semantic Status Colors ──
18
+ --status-success: var(--system-green);
19
+ --status-warning: var(--system-orange);
20
+ --status-error: var(--system-red);
21
+ --status-info: var(--system-blue);
22
+ --status-pending: var(--system-yellow);
23
+
24
+ // ── visionOS Typography ──
25
+ --font-family: 'SF Pro Display', 'SF Pro', 'Inter', -apple-system, blinkmacsystemfont, 'Segoe UI', sans-serif;
26
+ --font-xl-title1: 700 48px/56px var(--font-family);
27
+ --font-xl-title2: 700 38px/46px var(--font-family);
28
+ --font-large-title: 700 29px/38px var(--font-family);
29
+ --font-title1: 700 24px/32px var(--font-family);
30
+ --font-title2: 700 22px/28px var(--font-family);
31
+ --font-title3: 700 19px/24px var(--font-family);
32
+ --font-headline: 700 17px/22px var(--font-family);
33
+ --font-body: 510 17px/22px var(--font-family);
34
+ --font-callout: 590 15px/20px var(--font-family);
35
+ --font-subheadline: 400 15px/20px var(--font-family);
36
+ --font-footnote: 510 13px/18px var(--font-family);
37
+ --font-caption1: 510 12px/16px var(--font-family);
38
+ --font-caption2: 510 12px/16px var(--font-family);
39
+
40
+ // ── visionOS Label Colors ──
41
+ --label-primary: rgb(255 255 255 / 96%);
42
+ --label-secondary: rgb(255 255 255 / 56%);
43
+ --label-tertiary: rgb(255 255 255 / 36%);
44
+
45
+ // ── visionOS Materials ──
46
+ --material-glass: rgb(128 128 128 / 30%);
47
+ --material-glass-blur: 50px;
48
+ --material-glass-stroke: rgb(255 255 255 / 40%);
49
+ --material-glass-specular: inset 0px -0.5px 1px rgb(255 255 255 / 30%),
50
+ inset 0px -0.5px 1px rgb(255 255 255 / 25%),
51
+ inset 1px 1.5px 4px rgb(0 0 0 / 8%),
52
+ inset 1px 1.5px 4px rgb(0 0 0 / 10%);
53
+ --material-recessed-bg: linear-gradient(rgb(208 208 208 / 50%), rgb(208 208 208 / 50%)),
54
+ linear-gradient(rgb(0 0 0 / 10%), rgb(0 0 0 / 10%));
55
+ --material-recessed-shadow: inset 1px 1.5px 4px rgb(0 0 0 / 10%),
56
+ inset 1px 1.5px 4px rgb(0 0 0 / 8%),
57
+ inset 0px -0.5px 1px rgb(255 255 255 / 25%),
58
+ inset 0px -0.5px 1px rgb(255 255 255 / 30%);
59
+ --material-thin: rgb(255 255 255 / 6%);
60
+ --material-regular: rgb(255 255 255 / 12%);
61
+ --material-thick: rgb(255 255 255 / 20%);
62
+ --control-idle: rgb(255 255 255 / 6%);
63
+ --control-hover: rgb(255 255 255 / 12%);
64
+ --control-selected: rgb(255 255 255 / 100%);
65
+ --control-disabled: rgb(255 255 255 / 4%);
66
+ --separator: rgb(255 255 255 / 12%);
67
+ --blur-shadow-small: 0 2px 4px rgb(0 0 0 / 10%);
68
+
69
+ // ── visionOS Button Tokens ──
70
+ --btn-font-weight: 590;
71
+ --btn-symbol-font-weight: 510;
72
+ --btn-radius-capsule: 500px;
73
+ --btn-radius-rect-lg: 16px;
74
+ --btn-radius-rect-sm: 8px;
75
+ --btn-sm-height: 32px;
76
+ --btn-sm-padding: 0 12px;
77
+ --btn-sm-font-size: 15px;
78
+ --btn-sm-line-height: 20px;
79
+ --btn-sm-symbol-size: 17px;
80
+ --btn-sm-gap: 2px;
81
+ --btn-reg-height: 44px;
82
+ --btn-reg-padding: 0 20px;
83
+ --btn-reg-font-size: 17px;
84
+ --btn-reg-line-height: 22px;
85
+ --btn-reg-symbol-size: 19px;
86
+ --btn-reg-gap: 6px;
87
+ --btn-lg-height: 52px;
88
+ --btn-lg-padding: 0 25px;
89
+ --btn-lg-font-size: 19px;
90
+ --btn-lg-line-height: 24px;
91
+ --btn-lg-symbol-size: 22px;
92
+ --btn-lg-gap: 6px;
93
+ --btn-symbol-mini: 28px;
94
+ --btn-symbol-mini-font: 13px;
95
+ --btn-symbol-sm: 36px;
96
+ --btn-symbol-sm-font: 15px;
97
+ --btn-symbol-reg: 44px;
98
+ --btn-symbol-reg-font: 19px;
99
+ --btn-symbol-lg: 52px;
100
+ --btn-symbol-lg-font: 22px;
101
+ --btn-symbol-xl: 60px;
102
+ --btn-symbol-xl-font: 26px;
103
+ --btn-platter-lighten: rgb(255 255 255 / 6%);
104
+ --btn-platter-dodge: rgb(94 94 94 / 18%);
105
+ --btn-hover-grad-white: rgb(255 255 255 / 7%);
106
+ --btn-hover-grad-gray: rgb(94 94 94 / 14%);
107
+ --btn-disabled-lighten: rgb(255 255 255 / 4%);
108
+ --btn-disabled-dodge: rgb(94 94 94 / 7%);
109
+ --btn-disabled-text: rgb(112 112 112 / 50%);
110
+ --btn-selected-bg: rgb(255 255 255 / 96%);
111
+ --btn-selected-text: #000;
112
+ --link-color: #3CD3FE;
113
+ --link-height: 26px;
114
+ --link-font-size: 13px;
115
+ }
@@ -1213,16 +1213,135 @@ declare class FlyRemoteRouter {
1213
1213
  * In embedded mode: push a real browser history entry (so back/forward work)
1214
1214
  * and update the internal signal synchronously.
1215
1215
  *
1216
- * The state object carries `flyRemoteUrl` so the popstate listener can
1217
- * restore the exact URL without relying on window.location.pathname (which
1218
- * could be the shell's route, not the remote's logical URL).
1216
+ * The browser address bar is written as the shell's **canonical deep-link
1217
+ * form** `<shell-path>?app=<appId>&route=<remote-url>` NOT the bare remote
1218
+ * URL. This is what makes a hard reload work: on reload the shell's
1219
+ * `DeepLinkService` captures `?app=&route=` in its APP_INITIALIZER, re-opens
1220
+ * this app, and replays the route through the pending-launch pipeline
1221
+ * (`ShellLauncherService.launch` → `FLYOS_LAUNCH_EVENT` / pending registry →
1222
+ * the remote's root applies `ctx.route`). Writing the bare remote URL (e.g.
1223
+ * `/trends/abc`) instead would leave a host-unroutable path in the bar — on
1224
+ * reload the shell router falls through to its `**` wildcard, redirects to
1225
+ * `/desktop`, and the deep link is silently lost. See
1226
+ * skills/cross-app-deep-linking.md.
1227
+ *
1228
+ * `flyRemoteUrl` is still stashed in the history state so the popstate
1229
+ * listener restores the exact remote URL for back/forward without re-parsing
1230
+ * the query string.
1219
1231
  */
1220
1232
  private _pushEmbedded;
1233
+ /**
1234
+ * Build the browser-address-bar URL for an embedded navigation: the shell's
1235
+ * current path plus the canonical `?app=&route=` deep-link query (the same
1236
+ * contract `DeepLinkService.captureFromCurrentUrl` parses on cold load).
1237
+ *
1238
+ * The path is left untouched — only the query string carries the remote's
1239
+ * logical route — so the shell's own Angular Router (anchored at e.g.
1240
+ * `/desktop`) is never handed a path it cannot match.
1241
+ *
1242
+ * Fallback: when `appId` is unknown (WINDOW_DATA not injected — the Native
1243
+ * Federation token-split case where only `__FLYOS_SHELL__` proves embedding)
1244
+ * we cannot build a shareable link, so we return the shell path query-less.
1245
+ * Back/forward still work via the `flyRemoteUrl` history state; only
1246
+ * reload-restore is unavailable — no regression over leaving the bar as-is.
1247
+ */
1248
+ private _buildEmbeddedHistoryUrl;
1221
1249
  private buildUrl;
1222
1250
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyRemoteRouter, never>;
1223
1251
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<FlyRemoteRouter>;
1224
1252
  }
1225
1253
 
1254
+ /**
1255
+ * A federated remote's current navigation context, as published to the shell.
1256
+ *
1257
+ * `params` are the remote's **resolved route params** (e.g. `{ id: 'abc' }` for a
1258
+ * `trends/:id` match) — the remote owns its route table, so it resolves these and
1259
+ * the shell never has to know the remote's route patterns.
1260
+ */
1261
+ interface FlyRemoteContext {
1262
+ /** Owning app id — matches the shell's app registry and `AgentCommandScope.appId`. */
1263
+ readonly appId: string;
1264
+ /** Logical remote URL, e.g. `/trends/abc`. Query/hash stripped by the publisher. */
1265
+ readonly url: string;
1266
+ /** `url` split into path segments, e.g. `['trends', 'abc']`. */
1267
+ readonly segments: readonly string[];
1268
+ /** Resolved route params, e.g. `{ id: 'abc' }`. Empty when no param route matched. */
1269
+ readonly params: Readonly<Record<string, string>>;
1270
+ }
1271
+ /**
1272
+ * Shared cross-bundle store key + sync event. **Public contract** — a remote that
1273
+ * cannot consume a DS new enough to back {@link FlyRemoteContextService.publish} on
1274
+ * `globalThis` itself may write this slot directly (same shape, keyed by appId) and
1275
+ * dispatch {@link FLY_REMOTE_CONTEXT_EVENT} to notify the shell. Keep these literals
1276
+ * stable; they are an integration boundary, not an implementation detail.
1277
+ */
1278
+ declare const FLY_REMOTE_CONTEXT_STORE_KEY = "__flyRemoteContext__";
1279
+ declare const FLY_REMOTE_CONTEXT_EVENT = "fly:remote-context";
1280
+ /**
1281
+ * Remote → shell route/context channel.
1282
+ *
1283
+ * Why this exists
1284
+ * ---------------
1285
+ * A federated remote (e.g. Circles) renders inside a desktop-shell window and
1286
+ * keeps its own internal Angular route (`/trends/:id`). The shell cannot see that
1287
+ * route: the remote provides {@link FlyRemoteRouter} at its **component** injector
1288
+ * (so it can read per-window `WINDOW_DATA`), which makes the route state invisible
1289
+ * to the host. Shell-side features that need "what is the user looking at right
1290
+ * now" — most importantly Category-B slash commands whose `contextBindings` include
1291
+ * a `lookup`/`route` entity id — had no way to resolve the current entity id, and
1292
+ * degraded to "ask the user".
1293
+ *
1294
+ * The channel — why `globalThis`, not the DI singleton
1295
+ * ----------------------------------------------------
1296
+ * This service is `providedIn: 'root'`, but a root instance is **NOT** reliably
1297
+ * shared across the federation boundary. The shell builds the design system from
1298
+ * workspace SOURCE while remotes consume the PUBLISHED npm package; Native
1299
+ * Federation only collapses those two physical builds into one runtime instance if
1300
+ * version negotiation succeeds perfectly (matching advertised `mappingVersion`,
1301
+ * `singleton`, compatible ranges). That negotiation has silently split before —
1302
+ * giving the shell and a remote *separate* `providedIn:'root'` instances, so a
1303
+ * value published on one was invisible to the other.
1304
+ *
1305
+ * `globalThis` is the one substrate guaranteed shared across every federated bundle
1306
+ * in the same realm (there are no iframes), so the channel stores its state there
1307
+ * (see {@link FLY_REMOTE_CONTEXT_STORE_KEY}). {@link context} / {@link param} read
1308
+ * it directly — split-proof, synchronous, no injector-token gymnastics. A per-
1309
+ * instance signal mirrors the store for reactive consumers and is re-synced from a
1310
+ * `globalThis` event whenever any copy of the service (or a remote writing the slot
1311
+ * directly) mutates it. The same pattern already backs the shell's app-launch
1312
+ * context bridge, so this is an established boundary, not a new hack.
1313
+ *
1314
+ * Contract
1315
+ * --------
1316
+ * - Remote: call {@link publish} whenever its embedded route changes, and
1317
+ * {@link clear} on teardown (window close / component destroy).
1318
+ * - Shell: call {@link context} (or {@link param}) for an app id to resolve bindings.
1319
+ *
1320
+ * Keyed by `appId` (last publisher wins) — a single live window per app is the v1
1321
+ * assumption; a windowId key is the natural extension if multi-window-per-app
1322
+ * dispatch is ever needed.
1323
+ */
1324
+ declare class FlyRemoteContextService {
1325
+ private readonly _byApp;
1326
+ /** All currently-published contexts, keyed by app id. Reactive. */
1327
+ readonly contexts: _angular_core.Signal<ReadonlyMap<string, FlyRemoteContext>>;
1328
+ constructor();
1329
+ /** Publish (or replace) the active route context for an app. */
1330
+ publish(ctx: FlyRemoteContext): void;
1331
+ /** Drop an app's context (remote unmounted / window closed). No-op if absent. */
1332
+ clear(appId: string): void;
1333
+ /** Current context for an app, or `null` when nothing is published. */
1334
+ context(appId: string): FlyRemoteContext | null;
1335
+ /**
1336
+ * Resolve a single route param for an app, e.g. `param('circles', 'id')`.
1337
+ * Returns `null` when the app has no published context or the param is absent —
1338
+ * the caller then degrades (the skill asks for the missing id).
1339
+ */
1340
+ param(appId: string, path: string): string | null;
1341
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyRemoteContextService, never>;
1342
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<FlyRemoteContextService>;
1343
+ }
1344
+
1226
1345
  /**
1227
1346
  * Minimal adapter the shell (or any host) provides so design-system services can
1228
1347
  * look up apps without depending on `AppRegistryService` directly. Keeps the
@@ -1982,6 +2101,60 @@ interface AgentCommand {
1982
2101
  readonly executeOn: 'send';
1983
2102
  /** Optional client-side gate. Return false to hide the command in this scope. */
1984
2103
  readonly isVisible?: () => boolean;
2104
+ /**
2105
+ * Category B (PR3): when present, selecting this command invokes a
2106
+ * manifest-declared app skill instead of sending the composed text as a plain
2107
+ * message. The host dispatches a Twin message carrying
2108
+ * `system_context.slash_command_key = slashCommand.key` plus resolved context.
2109
+ * See {@link AgentCommandSlashSpec}.
2110
+ */
2111
+ readonly slashCommand?: AgentCommandSlashSpec;
2112
+ }
2113
+ /**
2114
+ * A context binding that resolves one `system_context` value for a Category B
2115
+ * command at dispatch. Pure data so it travels app-agnostically in the
2116
+ * Controller's app federation metadata (no callbacks). Discriminated by `from`:
2117
+ *
2118
+ * - `route` — value from the owning app's current route param `path`. The
2119
+ * shell cannot read a federated remote's internal route, so route
2120
+ * bindings **degrade** in v1 (the skill asks for the missing id);
2121
+ * resolved only once a remote→shell route channel exists.
2122
+ * - `lookup` — the host opens the `/lookup` entity picker for `entity` and
2123
+ * writes the picked id into `system_context[key]` (picker-during-
2124
+ * dispatch is a v1 follow-up — degrades to "ask" until then).
2125
+ * - `constant` — a literal value written into `system_context[key]`.
2126
+ */
2127
+ type AgentCommandContextBinding = {
2128
+ readonly key: string;
2129
+ readonly from: 'route';
2130
+ readonly path: string;
2131
+ } | {
2132
+ readonly key: string;
2133
+ readonly from: 'lookup';
2134
+ readonly entity: string;
2135
+ readonly exclude?: readonly string[];
2136
+ readonly promptKey?: string;
2137
+ } | {
2138
+ readonly key: string;
2139
+ readonly from: 'constant';
2140
+ readonly value: string;
2141
+ };
2142
+ /**
2143
+ * Category B slash-command dispatch metadata (PR3). Travels app-agnostically in
2144
+ * the Controller's app federation metadata and is registered by the shell's
2145
+ * `RemoteManifestService` (the same path that registers `/lookup` descriptors) —
2146
+ * remotes do NOT self-register. When an {@link AgentCommand} carries this,
2147
+ * selecting it dispatches a Twin message with `system_context.slash_command_key
2148
+ * = key`, merged with the resolved `contextBindings`.
2149
+ */
2150
+ interface AgentCommandSlashSpec {
2151
+ /** Dispatched as `system_context.slash_command_key`; matches the agents-side
2152
+ * skill's `slash_command_key` (= its manifest_key). */
2153
+ readonly key: string;
2154
+ /** Reserved: a future confirm step before dispatch (manifest `requiresConfirmation`). */
2155
+ readonly requiresConfirmation?: boolean;
2156
+ /** Parameter sources resolved into `system_context` at dispatch. */
2157
+ readonly contextBindings?: readonly AgentCommandContextBinding[];
1985
2158
  }
1986
2159
  /** What hosts pass to {@link AgentCommandRegistry.register}. Adds the scope to {@link AgentCommand}. */
1987
2160
  interface AgentCommandRegistration extends AgentCommand {
@@ -2021,6 +2194,20 @@ interface LookupSearch {
2021
2194
  readonly displayField: string;
2022
2195
  /** Optional response-item field for the chip's secondary line (status, category). */
2023
2196
  readonly secondaryField?: string;
2197
+ /**
2198
+ * Optional response-item field whose value is a *row-level* app id — i.e. the
2199
+ * app that owns this individual entity, distinct from the descriptor's
2200
+ * {@link LookupDescriptor.appId} (which only names the app exposing the
2201
+ * lookup endpoint). Help articles are the motivating case: every article is
2202
+ * exposed by `help-center`, but each one was seeded by a *source* app's
2203
+ * manifest (Circles, Trends, …). Surfacing that per-row appId lets the
2204
+ * picker render a second source-app tag so the user can tell two
2205
+ * similarly-titled rows from different source apps apart at a glance.
2206
+ *
2207
+ * Resolved through {@link LookupResult.appId} and the shell's app registry
2208
+ * with the same fallback chain used for {@link LookupDescriptor.appId}.
2209
+ */
2210
+ readonly appIdField?: string;
2024
2211
  /**
2025
2212
  * Dotted path to the results array within the response body when it is
2026
2213
  * wrapped, e.g. `items` for `{ items: [...], total }`. Omit when the response
@@ -2049,17 +2236,80 @@ interface LookupDescriptor {
2049
2236
  /** Optional PrimeIcons class for the picker row + chip. */
2050
2237
  readonly icon?: string;
2051
2238
  /**
2052
- * Route globs where this lookup is offered (matched against the shell's
2053
- * router url), e.g. `['/scenarios/*', '/trends/*']`. Omit / empty = offered
2054
- * everywhere the owning app is live.
2239
+ * Stable id of the app that exposes this lookup, e.g. `notes`, `calendar`,
2240
+ * `circles`. The picker resolves it to the app's display name via the shell's
2241
+ * app registry and renders an "exposed by …" badge so the user can see which
2242
+ * app owns the entity they're browsing (helps disambiguate when two apps
2243
+ * register a similar-sounding entity, e.g. both Tasks and Notes one day).
2244
+ *
2245
+ * Populated automatically by the shell's registration paths:
2246
+ * - `CORE_APP_LOOKUPS` stamps it per descriptor at hand-edit time.
2247
+ * - `RemoteManifestService` stamps it from the manifest entry's `id` so
2248
+ * federation remotes don't have to repeat the id in every descriptor.
2249
+ *
2250
+ * Falls back to {@link appBadgeKey} (a locale-resolved literal) when an
2251
+ * entity has no first-class home in the shell's app registry — e.g. `user`,
2252
+ * `app-agent`, `robot`. When neither is set the picker omits the badge.
2253
+ */
2254
+ readonly appId?: string;
2255
+ /**
2256
+ * Optional i18n key the picker uses for the "exposed by …" badge **when
2257
+ * {@link appId} is absent or unknown to the shell's app registry**. Lets
2258
+ * entities that don't map to a single app (Users, Robots, App Agents) still
2259
+ * surface a meaningful badge instead of silently omitting it. The picker
2260
+ * resolves the key via the shared i18n service so the badge follows the
2261
+ * user's locale.
2262
+ */
2263
+ readonly appBadgeKey?: string;
2264
+ /**
2265
+ * Advisory MCP tool-key prefixes the agent should prefer when the user
2266
+ * references this entity via `/lookup` (e.g. `['dashboard.reports']`). The
2267
+ * shell folds these into the turn's `mcp_scope` so the Twin self-serves the
2268
+ * owning app's tools — fetching and analysing the referenced entity itself —
2269
+ * instead of defaulting to a specialist-Robot consult for "tell me more"
2270
+ * style prompts. Same dot-namespaced prefix vocabulary as
2271
+ * {@link AgentMcpScope.apis}. Omit for entities with no first-class MCP tool
2272
+ * family (e.g. `user`, `robot`).
2273
+ */
2274
+ readonly mcpApis?: readonly string[];
2275
+ /**
2276
+ * Optional in-app deep-link route TEMPLATE for this entity's detail page,
2277
+ * e.g. `'/signals/{id}'`. When present, the desktop shell turns an agent's
2278
+ * inline reference to this entity — the `flyos:<appId>.<entity>/<id>`
2279
+ * anchors the agents backend emits in chat answers — into a launchable
2280
+ * link: the single `{id}` placeholder is substituted with the referenced
2281
+ * entity's id (URL-encoded) and the owning {@link appId} is launched on
2282
+ * that route via the shell launcher.
2283
+ *
2284
+ * Omit for entities with no standalone detail page — their references then
2285
+ * render as plain text (graceful degrade; never a dead link). The owning
2286
+ * app declares this once in its `lookups[]` manifest entry, so a remote
2287
+ * becomes agent-deep-linkable without any shell or design-system change.
2288
+ * Only `{id}` is substituted here — richer parameterisation rides the
2289
+ * deep-link `params` channel, not this template.
2055
2290
  */
2056
- readonly pages?: readonly string[];
2291
+ readonly deepLinkRoute?: string;
2057
2292
  /** How to fetch + map candidates. */
2058
2293
  readonly search: LookupSearch;
2059
2294
  }
2060
2295
  /** What hosts pass to the lookup registry. Adds the scope to {@link LookupDescriptor}. */
2061
2296
  interface LookupRegistration extends LookupDescriptor {
2062
- /** Same scoping semantics as {@link AgentCommandScope}. */
2297
+ /**
2298
+ * Affinity hint, NOT a visibility gate.
2299
+ *
2300
+ * Unlike {@link AgentCommandScope} — where `{appId}` HIDES a command unless the
2301
+ * app is live — lookup scope is a *priority hint*. Every registered lookup is
2302
+ * always offered in `/lookup`; when the app named by `{appId}` is in the host's
2303
+ * live app set, that lookup sorts to the **top** of the entity picker so the
2304
+ * "what am I working on right now?" entities surface first. `'global'` lookups
2305
+ * have no affinity and sort after app-affinity matches.
2306
+ *
2307
+ * Rationale: OS-core entities (note, calendar event, file) are always
2308
+ * referenceable — there's no "open the app first" condition the way there is
2309
+ * for federated remotes — so a visibility gate would just produce a confusing
2310
+ * empty state. Affinity-as-sort preserves the "Circles is open → prefer
2311
+ * scenarios/trends/signals" intuition without hiding the rest.
2312
+ */
2063
2313
  readonly scope: AgentCommandScope;
2064
2314
  }
2065
2315
  /** One resolved row the picker returns once the user selects a candidate. */
@@ -2072,6 +2322,14 @@ interface LookupResult {
2072
2322
  readonly label: string;
2073
2323
  /** Optional secondary detail (status / category). */
2074
2324
  readonly secondary?: string;
2325
+ /**
2326
+ * Row-level source app id (e.g. `circles` for an article seeded by Circles'
2327
+ * manifest). Populated when the descriptor sets {@link LookupSearch.appIdField}
2328
+ * and the response item carries a non-empty value. The picker renders it as
2329
+ * a second app tag alongside the descriptor-level badge so the user can see
2330
+ * "this Help-Center article was contributed by Circles" without opening it.
2331
+ */
2332
+ readonly appId?: string;
2075
2333
  }
2076
2334
  /** Disposable handle returned by the lookup registry. Idempotent `dispose()`. */
2077
2335
  interface LookupHandle {
@@ -2395,12 +2653,18 @@ declare class AgentCommandRegistry {
2395
2653
  /**
2396
2654
  * Singleton registry of entity lookups offered by the `/lookup` typeahead.
2397
2655
  *
2398
- * Mirrors {@link AgentCommandRegistry} exactly — same federation-singleton story
2399
- * (`sharedMappings: ['@mohamedatia/fly-design-system']`), same id-collision
2400
- * "latest wins" contract, same disposable-handle ergonomics. Federated remotes
2401
- * register their lookupable entities at boot (Circles: scenario / trend / signal)
2402
- * and dispose on window close, so the picker only ever offers entities whose app
2403
- * is currently live.
2656
+ * Mirrors {@link AgentCommandRegistry}'s federation-singleton story
2657
+ * (`sharedMappings: ['@mohamedatia/fly-design-system']`), id-collision
2658
+ * "latest wins" contract, and disposable-handle ergonomics. OS-core entities
2659
+ * (note / calendar event / file) register once at shell bootstrap via
2660
+ * `CORE_APP_LOOKUPS`; federated remotes (Circles: scenario / trend / signal)
2661
+ * register at remote-component boot and dispose on window close.
2662
+ *
2663
+ * **Scope semantics diverge from commands.** Commands HIDE when their `appId`
2664
+ * isn't in `liveAppIds`. Lookups DO NOT — they're always offered, and
2665
+ * `{appId}` is just a *priority hint* that bumps that lookup to the top of
2666
+ * the entity picker when the app is live. See {@link LookupRegistration.scope}
2667
+ * for the rationale.
2404
2668
  *
2405
2669
  * Storage is a signal store keyed on {@link LookupRegistration.entity}. Because
2406
2670
  * `entity` is the collision key, an app re-registering the same entity replaces
@@ -2411,10 +2675,18 @@ declare class AgentLookupRegistry {
2411
2675
  /** All currently-registered lookups, in insertion order. */
2412
2676
  readonly all: Signal<readonly LookupRegistration[]>;
2413
2677
  /**
2414
- * Lookups whose scope is `'global'` OR whose `scope.appId` is in the live app
2415
- * set. Recomputes when either the registry or `liveAppIds` changes — pass a
2678
+ * All registered lookups, sorted by affinity to `liveAppIds`:
2679
+ *
2680
+ * 1. Lookups whose `scope.appId` is in the live app set (in registration
2681
+ * order within that bucket).
2682
+ * 2. Then everything else — `'global'` lookups AND scoped lookups whose
2683
+ * app isn't currently live — in registration order.
2684
+ *
2685
+ * Recomputes when either the registry or `liveAppIds` changes. Pass a
2416
2686
  * `Signal<ReadonlySet<string>>` from the host's app-registry for reactive
2417
- * filtering, exactly like {@link AgentCommandRegistry.visible}.
2687
+ * re-sorting. **Always returns the full registry** — see the type doc on
2688
+ * {@link LookupRegistration.scope} for why this differs from
2689
+ * {@link AgentCommandRegistry.visible}.
2418
2690
  */
2419
2691
  visible(liveAppIds: ReadonlySet<string> | Signal<ReadonlySet<string>>): Signal<readonly LookupRegistration[]>;
2420
2692
  /**
@@ -2429,6 +2701,27 @@ declare class AgentLookupRegistry {
2429
2701
  * follow the standard "latest wins" rule and do NOT trigger rollback.
2430
2702
  */
2431
2703
  registerAll(lookups: readonly LookupRegistration[]): LookupHandle;
2704
+ /**
2705
+ * Resolve a deep-link anchor to a concrete launch target.
2706
+ *
2707
+ * `kind` is the dotted `<appId>.<entity>` token the agents backend emits
2708
+ * inside `flyos:<kind>/<id>` chat-answer anchors — the same entity-kind
2709
+ * vocabulary as drag-payload kinds and `ref` parts. Returns
2710
+ * `{ appId, route }` when a registered lookup for that `(appId, entity)`
2711
+ * pair carries a {@link LookupDescriptor.deepLinkRoute} template; `null`
2712
+ * otherwise (unknown entity, app mismatch, or no template — e.g. the
2713
+ * owning app isn't installed) so the caller renders plain text rather than
2714
+ * a dead link.
2715
+ *
2716
+ * `appId` and `entity` are both dot-free by their own grammars, so the
2717
+ * FIRST dot is the unambiguous split point; a dotless `kind` can't carry an
2718
+ * app and never resolves. The template's single `{id}` placeholder is
2719
+ * substituted URL-encoded.
2720
+ */
2721
+ resolveDeepLink(kind: string, id: string): {
2722
+ readonly appId: string;
2723
+ readonly route: string;
2724
+ } | null;
2432
2725
  /** Tear down by entity. Idempotent. */
2433
2726
  unregister(entity: string): void;
2434
2727
  /** Monotonic counter; identifies which registration call currently owns each entity. */
@@ -2975,6 +3268,6 @@ declare const AUDIENCE_ERROR_CODES: {
2975
3268
  };
2976
3269
  type AudienceErrorCode = (typeof AUDIENCE_ERROR_CODES)[keyof typeof AUDIENCE_ERROR_CODES];
2977
3270
 
2978
- export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DialogResult, FLYOS_LAUNCH_EVENT, FLY_LOCALE_CATALOG, FLY_REMOTE_BASE_PATH, FLY_REMOTE_ROUTES, FLY_THEME_MODE_IDS, FLY_WINDOW_HELP_HINT_EVENT, FlyAgentDraggableDirective, FlyBlockUiComponent, FlyFileUploadComponent, FlyImageUploadComponent, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySecureSrcDirective, FlyThemeService, FlyWindowHelpService, FlyosPendingLaunchesGlobalKey, I18nService, LAUNCH_CONTEXT, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowManagerService, findLocaleByDialect, findLocaleByPrefix, isRtlLocale, isRtlLocaleEntry, loadRemoteStyles, matchFlyRoutePattern, normalizeFlyTheme, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload };
2979
- export type { AgentAction, AgentActionDispatch, AgentActionVerb, AgentChipHostInputs, AgentCommand, AgentCommandHandle, AgentCommandRegistration, AgentCommandScope, AgentDragPayload, AgentDraggableItem, AgentDropChipMode, AgentDropRendererRegistration, AgentEnvelopeAttachment, AgentMcpScope, AgentMessageEnvelope, AgentPayloadLimits, AgentPayloadValidationResult, AppEveryonePrincipal, AppEveryoneTerm, AppLookup, AppLookupEntry, AudienceEditTarget, AudienceErrorCode, AudienceFilter, AudienceOptions, AudiencePresetKind, AudienceTerm, AudienceTermKind, ChartTerm, ChildWindowData, ContextMenuItem, ContextMenuSection, DesktopApp, DesktopAppKind, DialogResultWithAcknowledgement, FlyFileInfo, FlyLaunchEventDetail, FlyLocaleEntry, FlyRemoteMatch, FlyRemoteRoute, FlyThemeMode, FlyWindowHelpHintEventDetail, FlyWindowHelpPublisher, FlyosPendingLaunches, LaunchContext, LoadBundleOptions, LookupDescriptor, LookupHandle, LookupRegistration, LookupResult, LookupSearch, MessageBoxButton, MessageBoxDontAskAgainConfig, MessageBoxOptions, MessageBoxOptionsWithAcknowledgement, MockAuthConfig, OpenWindowOptions, OuPrincipal, OuTerm, PresetTerm, RemoteAppDef, RoleOuLookupRow, RolePrincipal, RolesTerm, ShareOrgChartOption, ShareOuNode, SharePanelLevelOption, SharePermissionEntry, SharePrincipal, SharePrincipalKind, ShareUserResult, User, UserPrincipal, UsersTerm, WindowHelpHint, WindowInstance, WindowState };
3271
+ export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DialogResult, FLYOS_LAUNCH_EVENT, FLY_LOCALE_CATALOG, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_ROUTES, FLY_THEME_MODE_IDS, FLY_WINDOW_HELP_HINT_EVENT, FlyAgentDraggableDirective, FlyBlockUiComponent, FlyFileUploadComponent, FlyImageUploadComponent, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySecureSrcDirective, FlyThemeService, FlyWindowHelpService, FlyosPendingLaunchesGlobalKey, I18nService, LAUNCH_CONTEXT, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowManagerService, findLocaleByDialect, findLocaleByPrefix, isRtlLocale, isRtlLocaleEntry, loadRemoteStyles, matchFlyRoutePattern, normalizeFlyTheme, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload };
3272
+ export type { AgentAction, AgentActionDispatch, AgentActionVerb, AgentChipHostInputs, AgentCommand, AgentCommandContextBinding, AgentCommandHandle, AgentCommandRegistration, AgentCommandScope, AgentCommandSlashSpec, AgentDragPayload, AgentDraggableItem, AgentDropChipMode, AgentDropRendererRegistration, AgentEnvelopeAttachment, AgentMcpScope, AgentMessageEnvelope, AgentPayloadLimits, AgentPayloadValidationResult, AppEveryonePrincipal, AppEveryoneTerm, AppLookup, AppLookupEntry, AudienceEditTarget, AudienceErrorCode, AudienceFilter, AudienceOptions, AudiencePresetKind, AudienceTerm, AudienceTermKind, ChartTerm, ChildWindowData, ContextMenuItem, ContextMenuSection, DesktopApp, DesktopAppKind, DialogResultWithAcknowledgement, FlyFileInfo, FlyLaunchEventDetail, FlyLocaleEntry, FlyRemoteContext, FlyRemoteMatch, FlyRemoteRoute, FlyThemeMode, FlyWindowHelpHintEventDetail, FlyWindowHelpPublisher, FlyosPendingLaunches, LaunchContext, LoadBundleOptions, LookupDescriptor, LookupHandle, LookupRegistration, LookupResult, LookupSearch, MessageBoxButton, MessageBoxDontAskAgainConfig, MessageBoxOptions, MessageBoxOptionsWithAcknowledgement, MockAuthConfig, OpenWindowOptions, OuPrincipal, OuTerm, PresetTerm, RemoteAppDef, RoleOuLookupRow, RolePrincipal, RolesTerm, ShareOrgChartOption, ShareOuNode, SharePanelLevelOption, SharePermissionEntry, SharePrincipal, SharePrincipalKind, ShareUserResult, User, UserPrincipal, UsersTerm, WindowHelpHint, WindowInstance, WindowState };
2980
3273
  //# sourceMappingURL=mohamedatia-fly-design-system.d.ts.map