@fiodos/cli 0.1.23 → 0.1.26

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/src/wireWeb.js CHANGED
@@ -27,6 +27,10 @@ const {
27
27
  registryRelImport,
28
28
  addRegistriesToMountSource,
29
29
  addRegistriesToBootstrapSource,
30
+ addSessionToMountSource,
31
+ addSessionToBootstrapSource,
32
+ addScreenToMountSource,
33
+ addScreenToBootstrapSource,
30
34
  buildEntryBootstrapBlock,
31
35
  IMPORT_NAME,
32
36
  WRAPPER_BASENAME,
@@ -499,6 +503,213 @@ function connectOrbRegistries(appRoot, opts = {}) {
499
503
  }
500
504
  }
501
505
 
506
+ /**
507
+ * Third pass — connect the generated SESSION module to the mounted orb, so the
508
+ * agent KNOWS whether the user is signed in (requiresAuth gate) and keys the
509
+ * conversation memory per user. Mirrors connectOrbRegistries: idempotent,
510
+ * reversible, never overrides a developer-wired isAuthenticated.
511
+ */
512
+ function connectOrbSession(appRoot, opts = {}) {
513
+ const { sessionFileAbs } = opts;
514
+ if (!sessionFileAbs || !fs.existsSync(sessionFileAbs)) return { status: 'no-session-file' };
515
+
516
+ // Only connect the capability getter when the generated module actually
517
+ // exports it — referencing a missing export would break the app's build.
518
+ let sessionHasCapabilities = false;
519
+ try {
520
+ sessionHasCapabilities = fs
521
+ .readFileSync(sessionFileAbs, 'utf8')
522
+ .includes('fyodosGetSessionCapabilities');
523
+ } catch {
524
+ sessionHasCapabilities = false;
525
+ }
526
+
527
+ const framework = detectFramework(appRoot);
528
+ const target = detectTarget(appRoot, framework);
529
+ if (!target || !target.file) return { status: 'no-target' };
530
+
531
+ const bootstrapKinds = new Set(['vue-entry', 'svelte-entry', 'sveltekit-hooks']);
532
+ if (bootstrapKinds.has(target.kind)) {
533
+ let source;
534
+ try {
535
+ source = fs.readFileSync(target.file, 'utf8');
536
+ } catch {
537
+ return { status: 'not-mounted' };
538
+ }
539
+ const importPath = registryRelImport(target.file, sessionFileAbs);
540
+ const fileRel = path.relative(appRoot, target.file);
541
+ const backups = backupFiles([target.file]);
542
+ try {
543
+ const res = addSessionToBootstrapSource(source, importPath, { sessionHasCapabilities });
544
+ if (!res.changed) {
545
+ return { status: res.reason === 'already' ? 'already' : res.reason || 'not-mounted', file: fileRel };
546
+ }
547
+ fs.writeFileSync(target.file, res.source);
548
+ return { status: 'connected', file: fileRel };
549
+ } catch (e) {
550
+ revertFiles(backups);
551
+ return { status: 'failed', file: fileRel, error: e };
552
+ }
553
+ }
554
+
555
+ const reactKinds = new Set(['vite', 'next-pages', 'next-app']);
556
+ if (!reactKinds.has(target.kind)) return { status: 'unsupported-framework', framework };
557
+
558
+ let mountFile = target.file;
559
+ if (target.kind === 'next-app') {
560
+ const dir = path.dirname(target.file);
561
+ mountFile =
562
+ [path.join(dir, `${WRAPPER_BASENAME}.tsx`), path.join(dir, `${WRAPPER_BASENAME}.jsx`)].find((f) =>
563
+ fs.existsSync(f),
564
+ ) || null;
565
+ if (!mountFile) return { status: 'not-mounted' };
566
+ }
567
+
568
+ let source;
569
+ try {
570
+ source = fs.readFileSync(mountFile, 'utf8');
571
+ } catch {
572
+ return { status: 'not-mounted' };
573
+ }
574
+ if (!/<FiodosAgent\b/.test(source)) return { status: 'not-mounted' };
575
+
576
+ const importPath = registryRelImport(mountFile, sessionFileAbs);
577
+ const fileRel = path.relative(appRoot, mountFile);
578
+ const backups = backupFiles([mountFile]);
579
+ try {
580
+ const res = addSessionToMountSource(source, importPath, { sessionHasCapabilities });
581
+ if (!res.changed) {
582
+ return { status: res.reason || 'not-mounted', file: fileRel };
583
+ }
584
+ fs.writeFileSync(mountFile, res.source);
585
+ return { status: 'connected', file: fileRel };
586
+ } catch (e) {
587
+ revertFiles(backups);
588
+ return { status: 'failed', file: fileRel, error: e };
589
+ }
590
+ }
591
+
592
+ /**
593
+ * Fourth pass — connect the generated SCREEN-TRUTH module to the mounted orb,
594
+ * so the agent knows WHICH SCREEN the user is on even when screens are client
595
+ * state instead of URLs. Mirrors connectOrbSession: idempotent, reversible,
596
+ * never overrides a developer-wired getCurrentRoute.
597
+ */
598
+ function connectOrbScreen(appRoot, opts = {}) {
599
+ const { screenFileAbs } = opts;
600
+ if (!screenFileAbs || !fs.existsSync(screenFileAbs)) return { status: 'no-screen-file' };
601
+
602
+ const framework = detectFramework(appRoot);
603
+ const target = detectTarget(appRoot, framework);
604
+ if (!target || !target.file) return { status: 'no-target' };
605
+
606
+ const bootstrapKinds = new Set(['vue-entry', 'svelte-entry', 'sveltekit-hooks']);
607
+ if (bootstrapKinds.has(target.kind)) {
608
+ let source;
609
+ try {
610
+ source = fs.readFileSync(target.file, 'utf8');
611
+ } catch {
612
+ return { status: 'not-mounted' };
613
+ }
614
+ const importPath = registryRelImport(target.file, screenFileAbs);
615
+ const fileRel = path.relative(appRoot, target.file);
616
+ const backups = backupFiles([target.file]);
617
+ try {
618
+ const res = addScreenToBootstrapSource(source, importPath);
619
+ if (!res.changed) {
620
+ return { status: res.reason === 'already' ? 'already' : res.reason || 'not-mounted', file: fileRel };
621
+ }
622
+ fs.writeFileSync(target.file, res.source);
623
+ return { status: 'connected', file: fileRel };
624
+ } catch (e) {
625
+ revertFiles(backups);
626
+ return { status: 'failed', file: fileRel, error: e };
627
+ }
628
+ }
629
+
630
+ const reactKinds = new Set(['vite', 'next-pages', 'next-app']);
631
+ if (!reactKinds.has(target.kind)) return { status: 'unsupported-framework', framework };
632
+
633
+ let mountFile = target.file;
634
+ if (target.kind === 'next-app') {
635
+ const dir = path.dirname(target.file);
636
+ mountFile =
637
+ [path.join(dir, `${WRAPPER_BASENAME}.tsx`), path.join(dir, `${WRAPPER_BASENAME}.jsx`)].find((f) =>
638
+ fs.existsSync(f),
639
+ ) || null;
640
+ if (!mountFile) return { status: 'not-mounted' };
641
+ }
642
+
643
+ let source;
644
+ try {
645
+ source = fs.readFileSync(mountFile, 'utf8');
646
+ } catch {
647
+ return { status: 'not-mounted' };
648
+ }
649
+ if (!/<FiodosAgent\b/.test(source)) return { status: 'not-mounted' };
650
+
651
+ const importPath = registryRelImport(mountFile, screenFileAbs);
652
+ const fileRel = path.relative(appRoot, mountFile);
653
+ const backups = backupFiles([mountFile]);
654
+ try {
655
+ const res = addScreenToMountSource(source, importPath);
656
+ if (!res.changed) {
657
+ return { status: res.reason || 'not-mounted', file: fileRel };
658
+ }
659
+ fs.writeFileSync(mountFile, res.source);
660
+ return { status: 'connected', file: fileRel };
661
+ } catch (e) {
662
+ revertFiles(backups);
663
+ return { status: 'failed', file: fileRel, error: e };
664
+ }
665
+ }
666
+
667
+ function reportScreenConnectResult(result, colors = {}, opts = {}) {
668
+ const quiet = opts.quiet !== false;
669
+ if (!result) return;
670
+ const { blue, cyan, dim, reset } = colors;
671
+ const tag = `${cyan || ''}◉${reset || ''} ${blue || ''}Fiodos${reset || ''}`;
672
+ switch (result.status) {
673
+ case 'connected':
674
+ console.error(`${tag} · screen truth connected to the orb mount (${result.file})`);
675
+ break;
676
+ case 'already':
677
+ if (!quiet) console.error(`${tag} · ${dim || ''}screen truth already connected to the mount${reset || ''}`);
678
+ break;
679
+ case 'dev-wired':
680
+ if (!quiet) {
681
+ console.error(`${tag} · ${dim || ''}the mount already has its own getCurrentRoute — left as is${reset || ''}`);
682
+ }
683
+ break;
684
+ default:
685
+ if (!quiet) console.error(`${tag} · ${dim || ''}screen truth not connected to the mount (${result.status})${reset || ''}`);
686
+ break;
687
+ }
688
+ }
689
+
690
+ function reportSessionConnectResult(result, colors = {}, opts = {}) {
691
+ const quiet = opts.quiet !== false;
692
+ if (!result) return;
693
+ const { blue, cyan, dim, reset } = colors;
694
+ const tag = `${cyan || ''}◉${reset || ''} ${blue || ''}Fiodos${reset || ''}`;
695
+ switch (result.status) {
696
+ case 'connected':
697
+ console.error(`${tag} · session connected to the orb mount (${result.file})`);
698
+ break;
699
+ case 'already':
700
+ if (!quiet) console.error(`${tag} · ${dim || ''}session already connected to the mount${reset || ''}`);
701
+ break;
702
+ case 'dev-wired':
703
+ if (!quiet) {
704
+ console.error(`${tag} · ${dim || ''}the mount already has its own isAuthenticated — left as is${reset || ''}`);
705
+ }
706
+ break;
707
+ default:
708
+ if (!quiet) console.error(`${tag} · ${dim || ''}session not connected to the mount (${result.status})${reset || ''}`);
709
+ break;
710
+ }
711
+ }
712
+
502
713
  function reportRegistriesResult(result, colors = {}, opts = {}) {
503
714
  const quiet = opts.quiet !== false;
504
715
  if (!result) return;
@@ -530,6 +741,10 @@ module.exports = {
530
741
  reportWireResult,
531
742
  connectOrbRegistries,
532
743
  reportRegistriesResult,
744
+ connectOrbSession,
745
+ reportSessionConnectResult,
746
+ connectOrbScreen,
747
+ reportScreenConnectResult,
533
748
  detectFramework,
534
749
  detectTarget,
535
750
  };
@@ -83,19 +83,45 @@ function insertBlockAfterLastImport(source, block) {
83
83
  // FYODOS:ORB markers → idempotent (re-runs strip & rewrite) and reversible.
84
84
  const BOOTSTRAP_ALIAS = '__fiodosCreateAgent';
85
85
  const BOOTSTRAP_REGISTRY_EXPORT = 'fyodosGeneratedRegistries';
86
+ // Exports of the generated session module (see wireSession.js). Connected to
87
+ // the mount automatically so auth awareness needs NO manual step.
88
+ const SESSION_IS_AUTH_EXPORT = 'fyodosIsAuthenticated';
89
+ const SESSION_USER_ID_EXPORT = 'fyodosGetUserId';
90
+ // Capability flags (audience map) — only connected when the generated session
91
+ // module actually exports it (older generated files do not).
92
+ const SESSION_CAPS_EXPORT = 'fyodosGetSessionCapabilities';
93
+ // Export of the generated screen-truth module (see wireScreen.js). Connected
94
+ // to the mount automatically so state-driven screen awareness needs NO manual step.
95
+ const SCREEN_ROUTE_EXPORT = 'fyodosGetCurrentRoute';
86
96
 
87
97
  function buildEntryBootstrapBlock(opts = {}) {
88
- const { registryImportPath } = opts;
98
+ const { registryImportPath, sessionImportPath, screenImportPath, sessionHasCapabilities } = opts;
89
99
  const lines = [];
90
100
  lines.push(ORB_SCRIPT_START);
91
101
  lines.push(`import { createFiodosAgent as ${BOOTSTRAP_ALIAS} } from '@fiodos/web-core';`);
92
102
  if (registryImportPath) {
93
103
  lines.push(`import { ${BOOTSTRAP_REGISTRY_EXPORT} } from '${registryImportPath}';`);
94
104
  }
105
+ if (sessionImportPath) {
106
+ const sessionNames = [SESSION_IS_AUTH_EXPORT, SESSION_USER_ID_EXPORT];
107
+ if (sessionHasCapabilities) sessionNames.push(SESSION_CAPS_EXPORT);
108
+ lines.push(`import { ${sessionNames.join(', ')} } from '${sessionImportPath}';`);
109
+ }
110
+ if (screenImportPath) {
111
+ lines.push(`import { ${SCREEN_ROUTE_EXPORT} } from '${screenImportPath}';`);
112
+ }
95
113
  lines.push(`${BOOTSTRAP_ALIAS}({`);
96
114
  lines.push(' apiKey: import.meta.env.VITE_FYODOS_API_KEY,');
97
115
  lines.push(' baseUrl: import.meta.env.VITE_FYODOS_API_URL,');
98
116
  if (registryImportPath) lines.push(` registries: ${BOOTSTRAP_REGISTRY_EXPORT},`);
117
+ if (sessionImportPath) {
118
+ lines.push(` isAuthenticated: ${SESSION_IS_AUTH_EXPORT},`);
119
+ lines.push(` getUserId: ${SESSION_USER_ID_EXPORT},`);
120
+ if (sessionHasCapabilities) {
121
+ lines.push(` getSessionCapabilities: ${SESSION_CAPS_EXPORT},`);
122
+ }
123
+ }
124
+ if (screenImportPath) lines.push(` getCurrentRoute: ${SCREEN_ROUTE_EXPORT},`);
99
125
  lines.push(' mount: true,');
100
126
  lines.push('});');
101
127
  lines.push(ORB_SCRIPT_END);
@@ -123,8 +149,70 @@ function addRegistriesToBootstrapSource(source, registryImportPath) {
123
149
  if (/\n\s*registries:\s/.test(source.slice(source.indexOf(ORB_SCRIPT_START)))) {
124
150
  return { changed: false, source, reason: 'already' };
125
151
  }
152
+ // Preserve session/screen connections previous passes already added.
153
+ const sessionImportPath = extractBootstrapImportPath(source, SESSION_IS_AUTH_EXPORT);
154
+ const sessionHasCapabilities = Boolean(extractBootstrapImportPath(source, SESSION_CAPS_EXPORT));
155
+ const screenImportPath = extractBootstrapImportPath(source, SCREEN_ROUTE_EXPORT);
126
156
  const stripped = stripMarkedRegion(source, ORB_SCRIPT_START, ORB_SCRIPT_END).replace(/\n{3,}$/, '\n');
127
- const block = buildEntryBootstrapBlock({ registryImportPath });
157
+ const block = buildEntryBootstrapBlock({
158
+ registryImportPath,
159
+ sessionImportPath,
160
+ screenImportPath,
161
+ sessionHasCapabilities,
162
+ });
163
+ const next = insertBlockAfterLastImport(stripped.trimEnd(), block);
164
+ return { changed: true, source: next.endsWith('\n') ? next : `${next}\n` };
165
+ }
166
+
167
+ // Import path of the module that exports `name` inside our bootstrap block (or null).
168
+ function extractBootstrapImportPath(source, name) {
169
+ const startIdx = source.indexOf(ORB_SCRIPT_START);
170
+ if (startIdx === -1) return null;
171
+ const endIdx = source.indexOf(ORB_SCRIPT_END, startIdx);
172
+ const block = source.slice(startIdx, endIdx === -1 ? undefined : endIdx);
173
+ const m = block.match(new RegExp(`import\\s*\\{[^}]*\\b${name}\\b[^}]*\\}\\s*from\\s*['"]([^'"]+)['"]`));
174
+ return m ? m[1] : null;
175
+ }
176
+
177
+ // Idempotently rewrite an existing entry-bootstrap block to carry the generated
178
+ // SESSION connection (third pass, after session wiring). Preserves the
179
+ // registries the second pass added. Returns { changed, source, reason? }.
180
+ function addSessionToBootstrapSource(source, sessionImportPath, opts = {}) {
181
+ if (!source.includes(ORB_SCRIPT_START)) return { changed: false, source, reason: 'not-mounted' };
182
+ if (/\n\s*isAuthenticated:\s/.test(source.slice(source.indexOf(ORB_SCRIPT_START)))) {
183
+ return { changed: false, source, reason: 'already' };
184
+ }
185
+ const registryImportPath = extractBootstrapImportPath(source, BOOTSTRAP_REGISTRY_EXPORT);
186
+ const screenImportPath = extractBootstrapImportPath(source, SCREEN_ROUTE_EXPORT);
187
+ const stripped = stripMarkedRegion(source, ORB_SCRIPT_START, ORB_SCRIPT_END).replace(/\n{3,}$/, '\n');
188
+ const block = buildEntryBootstrapBlock({
189
+ registryImportPath,
190
+ sessionImportPath,
191
+ screenImportPath,
192
+ sessionHasCapabilities: Boolean(opts.sessionHasCapabilities),
193
+ });
194
+ const next = insertBlockAfterLastImport(stripped.trimEnd(), block);
195
+ return { changed: true, source: next.endsWith('\n') ? next : `${next}\n` };
196
+ }
197
+
198
+ // Idempotently rewrite an existing entry-bootstrap block to carry the generated
199
+ // SCREEN-TRUTH connection (fourth pass, after screen wiring). Preserves the
200
+ // registries and session earlier passes added. Returns { changed, source, reason? }.
201
+ function addScreenToBootstrapSource(source, screenImportPath) {
202
+ if (!source.includes(ORB_SCRIPT_START)) return { changed: false, source, reason: 'not-mounted' };
203
+ if (/\n\s*getCurrentRoute:\s/.test(source.slice(source.indexOf(ORB_SCRIPT_START)))) {
204
+ return { changed: false, source, reason: 'already' };
205
+ }
206
+ const registryImportPath = extractBootstrapImportPath(source, BOOTSTRAP_REGISTRY_EXPORT);
207
+ const sessionImportPath = extractBootstrapImportPath(source, SESSION_IS_AUTH_EXPORT);
208
+ const sessionHasCapabilities = Boolean(extractBootstrapImportPath(source, SESSION_CAPS_EXPORT));
209
+ const stripped = stripMarkedRegion(source, ORB_SCRIPT_START, ORB_SCRIPT_END).replace(/\n{3,}$/, '\n');
210
+ const block = buildEntryBootstrapBlock({
211
+ registryImportPath,
212
+ sessionImportPath,
213
+ screenImportPath,
214
+ sessionHasCapabilities,
215
+ });
128
216
  const next = insertBlockAfterLastImport(stripped.trimEnd(), block);
129
217
  return { changed: true, source: next.endsWith('\n') ? next : `${next}\n` };
130
218
  }
@@ -199,6 +287,74 @@ function addRegistriesToMountSource(source, exportName, importPath) {
199
287
  return { changed: true, source: next };
200
288
  }
201
289
 
290
+ // Idempotently connect the generated SESSION module to the mounted
291
+ // <FiodosAgent/>: adds `isAuthenticated={fyodosIsAuthenticated}` and
292
+ // `getUserId={fyodosGetUserId}` + the import. Skips (never overrides) a mount
293
+ // where the developer already wired their own isAuthenticated. Same
294
+ // reversibility model as addRegistriesToMountSource.
295
+ function addSessionToMountSource(source, importPath, opts = {}) {
296
+ const withCapabilities = Boolean(opts.sessionHasCapabilities);
297
+ const tagRe = /([ \t]*)<FiodosAgent\b[\s\S]*?\/>/;
298
+ const m = source.match(tagRe);
299
+ if (!m) return { changed: false, source, reason: 'not-mounted' };
300
+ const tag = m[0];
301
+ if (new RegExp(`isAuthenticated=\\{${escapeRe(SESSION_IS_AUTH_EXPORT)}\\}`).test(tag)) {
302
+ return { changed: false, source, reason: 'already' };
303
+ }
304
+ if (/\bisAuthenticated=/.test(tag)) {
305
+ return { changed: false, source, reason: 'dev-wired' };
306
+ }
307
+ const baseIndent = m[1] || '';
308
+ const propMatch = tag.match(/\n([ \t]*)(?:apiKey|api-key|apiUrl|baseUrl|registries)/);
309
+ const propIndent = propMatch ? propMatch[1] : `${baseIndent} `;
310
+ const hasUserId = /\bgetUserId=/.test(tag);
311
+ const addCaps = withCapabilities && !/\bgetSessionCapabilities=/.test(tag);
312
+ const props =
313
+ `\n${propIndent}isAuthenticated={${SESSION_IS_AUTH_EXPORT}}` +
314
+ (hasUserId ? '' : `\n${propIndent}getUserId={${SESSION_USER_ID_EXPORT}}`) +
315
+ (addCaps ? `\n${propIndent}getSessionCapabilities={${SESSION_CAPS_EXPORT}}` : '');
316
+ const newTag = tag.replace(/\n?[ \t]*\/>$/, `${props}\n${baseIndent}/>`);
317
+ let next = source.replace(tag, newTag);
318
+ const nameList = [SESSION_IS_AUTH_EXPORT];
319
+ if (!hasUserId) nameList.push(SESSION_USER_ID_EXPORT);
320
+ if (addCaps) nameList.push(SESSION_CAPS_EXPORT);
321
+ const importLine = `import { ${nameList.join(', ')} } from '${importPath}';`;
322
+ if (!next.includes(importLine)) {
323
+ next = insertImportAfterLastImport(next, importLine);
324
+ }
325
+ return { changed: true, source: next };
326
+ }
327
+
328
+ // Idempotently connect the generated SCREEN-TRUTH module to the mounted
329
+ // <FiodosAgent/>: adds `getCurrentRoute={fyodosGetCurrentRoute}` + the import.
330
+ // Skips (never overrides) a mount where the developer already wired their own
331
+ // getCurrentRoute. Same reversibility model as addSessionToMountSource.
332
+ function addScreenToMountSource(source, importPath) {
333
+ const tagRe = /([ \t]*)<FiodosAgent\b[\s\S]*?\/>/;
334
+ const m = source.match(tagRe);
335
+ if (!m) return { changed: false, source, reason: 'not-mounted' };
336
+ const tag = m[0];
337
+ if (new RegExp(`getCurrentRoute=\\{${escapeRe(SCREEN_ROUTE_EXPORT)}\\}`).test(tag)) {
338
+ return { changed: false, source, reason: 'already' };
339
+ }
340
+ if (/\bgetCurrentRoute=/.test(tag)) {
341
+ return { changed: false, source, reason: 'dev-wired' };
342
+ }
343
+ const baseIndent = m[1] || '';
344
+ const propMatch = tag.match(/\n([ \t]*)(?:apiKey|api-key|apiUrl|baseUrl|registries)/);
345
+ const propIndent = propMatch ? propMatch[1] : `${baseIndent} `;
346
+ const newTag = tag.replace(
347
+ /\n?[ \t]*\/>$/,
348
+ `\n${propIndent}getCurrentRoute={${SCREEN_ROUTE_EXPORT}}\n${baseIndent}/>`,
349
+ );
350
+ let next = source.replace(tag, newTag);
351
+ const importLine = `import { ${SCREEN_ROUTE_EXPORT} } from '${importPath}';`;
352
+ if (!next.includes(importLine)) {
353
+ next = insertImportAfterLastImport(next, importLine);
354
+ }
355
+ return { changed: true, source: next };
356
+ }
357
+
202
358
  /**
203
359
  * Assess whether we can inject safely. Returns { ok, reason?, strategy, files, rel }.
204
360
  */
@@ -601,13 +757,15 @@ function writeConsentDoc(appRoot, plan) {
601
757
  'Edits sit between `FYODOS:ORB:START` / `FYODOS:ORB:END` markers. Remove those',
602
758
  'blocks (and the Fiodos import) to revert.',
603
759
  '',
604
- '## Apps with login (connect auth + screenthe only manual step)',
760
+ '## Apps with login (auth + identitywired AUTOMATICALLY)',
761
+ '',
762
+ 'For apps with login the installer also detects WHERE your session state lives',
763
+ 'and connects it on its own: it generates `src/fyodos/session.generated.*` and',
764
+ 'adds `isAuthenticated={fyodosIsAuthenticated}` / `getUserId={fyodosGetUserId}`',
765
+ 'to the mount (see `src/fyodos/FYODOS_SESSION.md`). Nothing to do by hand.',
605
766
  '',
606
- 'The orb runs with just `apiKey`/`apiUrl`. But only YOUR app knows whether the',
607
- 'user is signed in and which screen they are on, so for apps with login you',
608
- 'connect that in one place. Without it the agent can loop ("do you want to sign',
609
- "in?\") and can't tell it already signed you in. Add these props to",
610
- '`<FiodosAgent/>` (a commented scaffold is already next to the mount):',
767
+ 'ONLY if the installer reported it could not verify your session source (or you',
768
+ 'want to override it), wire the props yourself:',
611
769
  '',
612
770
  '```tsx',
613
771
  '<FiodosAgent',
@@ -653,7 +811,12 @@ module.exports = {
653
811
  registryRelImport,
654
812
  addRegistriesToMountSource,
655
813
  addRegistriesToBootstrapSource,
814
+ addSessionToMountSource,
815
+ addSessionToBootstrapSource,
816
+ addScreenToMountSource,
817
+ addScreenToBootstrapSource,
656
818
  buildEntryBootstrapBlock,
657
819
  IMPORT_NAME,
658
820
  WRAPPER_BASENAME,
821
+ SESSION_CAPS_EXPORT,
659
822
  };