@ateam-ai-mobile/core 0.1.4 → 0.1.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai-mobile/core",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Headless ADAS SDK core — auth bridge, API client, chat/job streaming, MCP calls, theme tokens. No UI, no Expo dependencies.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/chat/store.ts CHANGED
@@ -182,7 +182,16 @@ function renderTableShape(content: any): string | null {
182
182
  */
183
183
  export function blocksToText(blocks?: Array<{ kind: string; content: any }>): string {
184
184
  if (!blocks || blocks.length === 0) return '';
185
+ // Mirror the web renderer: when a human-readable text/markdown block exists in
186
+ // the same turn, drop internal-state json/code blocks (planning state,
187
+ // askUser payloads) — otherwise they render as a raw ```json blob AFTER the
188
+ // real answer. Standalone json/code (no text block, e.g. a table-only turn)
189
+ // still renders as before.
190
+ const hasTextBlock = blocks.some(
191
+ b => b.kind === 'text' || b.kind === 'markdown' || b.kind === 'description',
192
+ );
185
193
  return blocks.map(b => {
194
+ if ((b.kind === 'json' || b.kind === 'code') && hasTextBlock) return '';
186
195
  if (b.kind === 'text' || b.kind === 'markdown' || b.kind === 'description') {
187
196
  return typeof b.content === 'string' ? b.content : '';
188
197
  }
package/src/index.ts CHANGED
@@ -44,6 +44,8 @@ export {
44
44
  } from './api/mcp';
45
45
 
46
46
  // Tenant memberships
47
+ export { getSession, isDevHost } from './session';
48
+ export type { Session, SessionEnv } from './session';
47
49
  export { listMyTenants, switchTenant } from './api/tenants';
48
50
  export type { TenantMembership } from './api/tenants';
49
51
 
package/src/session.ts ADDED
@@ -0,0 +1,62 @@
1
+ // packages/core/src/session.ts
2
+ //
3
+ // THE single answer to "where am I / what am I talking to / who am I", derived
4
+ // from the SDK config the REQUESTS themselves use — getTenant / getConsumerAuthApiUrl
5
+ // / getCoreApiUrl / getUser. Because the label reads from the same place the
6
+ // request reads, they cannot disagree. Host-agnostic: any host that calls
7
+ // initAdas() gets a correct session with no parallel copy to drift.
8
+ //
9
+ // Rule: DERIVE, NEVER STORE — see Docs/DERIVE_NEVER_STORE.md. This lives in the
10
+ // SDK (not a host app) so iOS/Android/RN hosts share one derivation; the host's
11
+ // React hook (e.g. useSession) is a thin wrapper that just re-renders on change.
12
+
13
+ import { getTenant, getConsumerAuthApiUrl, getCoreApiUrl, getUser } from './config';
14
+
15
+ export type SessionEnv = 'dev' | 'prod';
16
+
17
+ export interface Session {
18
+ /** Tenant slug the app is actually scoped to (getTenant = signed-in tenant,
19
+ * falling back to the pre-auth choice). Null when neither is set. */
20
+ tenant: string | null;
21
+ /** Human label for the tenant — slug today; callers must not compute their own. */
22
+ tenantName: string;
23
+ /** dev | prod — derived from the resolved host, never a stored word. */
24
+ env: SessionEnv;
25
+ /** The actual backend host — a host can't be ambiguous the way a word can. */
26
+ host: string;
27
+ actorId: string | null;
28
+ email: string | null;
29
+ }
30
+
31
+ function hostOf(u: string | undefined | null): string {
32
+ if (!u) return '';
33
+ try { return new URL(u).host; } catch { return u; }
34
+ }
35
+
36
+ /** Is a resolved base URL a dev backend? Keyed on the hostname (dev-app…,
37
+ * dev-consumer-auth…) so it matches wherever the request goes. */
38
+ export function isDevHost(u: string | undefined | null): boolean {
39
+ const h = hostOf(u);
40
+ return !!h && (h.includes('dev-') || /(^|\.)dev\./.test(h));
41
+ }
42
+
43
+ /** Compute the session from the live SDK config. Plain function — a host hook
44
+ * wraps this for reactivity; imperative code can call it directly. */
45
+ export function getSession(): Session {
46
+ let consumerUrl = '';
47
+ try { consumerUrl = getConsumerAuthApiUrl(); } catch { /* not configured yet */ }
48
+ let coreUrl = '';
49
+ try { coreUrl = getCoreApiUrl(); } catch { /* not configured yet */ }
50
+
51
+ const tenant = getTenant() || null;
52
+ const user = getUser();
53
+
54
+ return {
55
+ tenant,
56
+ tenantName: tenant || '—',
57
+ env: isDevHost(consumerUrl) || isDevHost(coreUrl) ? 'dev' : 'prod',
58
+ host: hostOf(consumerUrl || coreUrl),
59
+ actorId: user?.actorId ?? null,
60
+ email: user?.email ?? null,
61
+ };
62
+ }