@frankieai/core 0.2.5 → 0.2.7

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/dist/index.d.cts CHANGED
@@ -95,6 +95,10 @@ declare const featuresConfigSchema: z.ZodPrefault<z.ZodObject<{
95
95
  }, z.core.$strip>>;
96
96
  workspaceAdmin: z.ZodDefault<z.ZodBoolean>;
97
97
  configurationAssistant: z.ZodDefault<z.ZodBoolean>;
98
+ escalation: z.ZodPrefault<z.ZodObject<{
99
+ enabled: z.ZodDefault<z.ZodBoolean>;
100
+ webhookUrl: z.ZodOptional<z.ZodString>;
101
+ }, z.core.$strip>>;
98
102
  }, z.core.$strip>>;
99
103
  declare const mcpServerSchema: z.ZodObject<{
100
104
  name: z.ZodString;
@@ -104,6 +108,7 @@ declare const mcpServerSchema: z.ZodObject<{
104
108
  discoveredTools: z.ZodDefault<z.ZodArray<z.ZodObject<{
105
109
  name: z.ZodString;
106
110
  description: z.ZodOptional<z.ZodString>;
111
+ inputs: z.ZodOptional<z.ZodString>;
107
112
  }, z.core.$strip>>>;
108
113
  transport: z.ZodDefault<z.ZodEnum<{
109
114
  http: "http";
@@ -131,6 +136,7 @@ declare const apiCapabilitySchema: z.ZodObject<{
131
136
  }>;
132
137
  path: z.ZodString;
133
138
  summary: z.ZodOptional<z.ZodString>;
139
+ inputs: z.ZodOptional<z.ZodString>;
134
140
  authGap: z.ZodDefault<z.ZodBoolean>;
135
141
  }, z.core.$strip>;
136
142
  declare const apiSourceSchema: z.ZodObject<{
@@ -165,6 +171,7 @@ declare const apiSourceSchema: z.ZodObject<{
165
171
  }>;
166
172
  path: z.ZodString;
167
173
  summary: z.ZodOptional<z.ZodString>;
174
+ inputs: z.ZodOptional<z.ZodString>;
168
175
  authGap: z.ZodDefault<z.ZodBoolean>;
169
176
  }, z.core.$strip>>>;
170
177
  headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -269,6 +276,109 @@ declare const brandingConfigSchema: z.ZodObject<{
269
276
  avatarUrl: z.ZodOptional<z.ZodString>;
270
277
  launcherLabel: z.ZodDefault<z.ZodString>;
271
278
  }, z.core.$strip>;
279
+ /**
280
+ * Knowledge base: documentation the agent answers from. Each source is an entry
281
+ * URL Frankie crawls (same-origin, bounded) to build a semantic index; the
282
+ * chunks + embeddings live in the knowledge store, not in this config. Enabling
283
+ * it gives the agent a `frankie__docs__search` tool and grounds its answers.
284
+ */
285
+ declare const knowledgeSourceSchema: z.ZodObject<{
286
+ url: z.ZodString;
287
+ }, z.core.$strip>;
288
+ declare const knowledgeBaseSchema: z.ZodPrefault<z.ZodObject<{
289
+ enabled: z.ZodDefault<z.ZodBoolean>;
290
+ sources: z.ZodDefault<z.ZodArray<z.ZodObject<{
291
+ url: z.ZodString;
292
+ }, z.core.$strip>>>;
293
+ maxPages: z.ZodDefault<z.ZodNumber>;
294
+ }, z.core.$strip>>;
295
+ /**
296
+ * An additional embedded agent on the same workspace. Frankie is one-agent-per
297
+ * publishable-key: a persona carries its OWN key, so the data plane still
298
+ * resolves one key to one agent (see `resolvePersonaConfig`). A persona overrides
299
+ * the distinct slice of a config — its branding, agent copy, capabilities and
300
+ * knowledge base — while sharing the workspace's auth, model, origins and tools.
301
+ * `pagePatterns` says which routes the persona shows on (e.g. support on "/",
302
+ * docs on "/docs/**"). It is served in `/v1/config` as `pages`, and the
303
+ * generated `FrankieAgents` mount reads it at runtime, so changing it never
304
+ * needs a new install PR.
305
+ */
306
+ declare const personaProfileSchema: z.ZodObject<{
307
+ id: z.ZodString;
308
+ label: z.ZodString;
309
+ publishableKey: z.ZodString;
310
+ pagePatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
311
+ allowAnonymous: z.ZodOptional<z.ZodBoolean>;
312
+ scope: z.ZodOptional<z.ZodString>;
313
+ contactUrl: z.ZodOptional<z.ZodString>;
314
+ branding: z.ZodOptional<z.ZodObject<{
315
+ name: z.ZodOptional<z.ZodString>;
316
+ tagline: z.ZodOptional<z.ZodString>;
317
+ avatarUrl: z.ZodOptional<z.ZodString>;
318
+ launcherLabel: z.ZodOptional<z.ZodString>;
319
+ }, z.core.$strip>>;
320
+ agent: z.ZodPrefault<z.ZodObject<{
321
+ systemPrompt: z.ZodDefault<z.ZodString>;
322
+ greeting: z.ZodDefault<z.ZodString>;
323
+ suggestedPrompts: z.ZodDefault<z.ZodArray<z.ZodString>>;
324
+ starterPrompts: z.ZodDefault<z.ZodArray<z.ZodObject<{
325
+ title: z.ZodString;
326
+ description: z.ZodOptional<z.ZodString>;
327
+ message: z.ZodString;
328
+ icon: z.ZodOptional<z.ZodEnum<{
329
+ file: "file";
330
+ sparkles: "sparkles";
331
+ wand: "wand";
332
+ book: "book";
333
+ chat: "chat";
334
+ chart: "chart";
335
+ bolt: "bolt";
336
+ music: "music";
337
+ mic: "mic";
338
+ image: "image";
339
+ compass: "compass";
340
+ lightbulb: "lightbulb";
341
+ }>>;
342
+ }, z.core.$strip>>>;
343
+ maxTurns: z.ZodDefault<z.ZodNumber>;
344
+ maxBudgetUsd: z.ZodOptional<z.ZodNumber>;
345
+ tools: z.ZodPrefault<z.ZodObject<{
346
+ allow: z.ZodDefault<z.ZodArray<z.ZodString>>;
347
+ deny: z.ZodDefault<z.ZodArray<z.ZodString>>;
348
+ denyByDefault: z.ZodDefault<z.ZodBoolean>;
349
+ }, z.core.$strip>>;
350
+ showToolActivity: z.ZodDefault<z.ZodBoolean>;
351
+ }, z.core.$strip>>;
352
+ features: z.ZodPrefault<z.ZodObject<{
353
+ attachments: z.ZodPrefault<z.ZodObject<{
354
+ enabled: z.ZodDefault<z.ZodBoolean>;
355
+ accept: z.ZodDefault<z.ZodArray<z.ZodString>>;
356
+ maxMb: z.ZodDefault<z.ZodNumber>;
357
+ maxCount: z.ZodDefault<z.ZodNumber>;
358
+ }, z.core.$strip>>;
359
+ modelPicker: z.ZodPrefault<z.ZodObject<{
360
+ enabled: z.ZodDefault<z.ZodBoolean>;
361
+ models: z.ZodDefault<z.ZodArray<z.ZodObject<{
362
+ id: z.ZodString;
363
+ label: z.ZodString;
364
+ provider: z.ZodOptional<z.ZodString>;
365
+ }, z.core.$strip>>>;
366
+ }, z.core.$strip>>;
367
+ workspaceAdmin: z.ZodDefault<z.ZodBoolean>;
368
+ configurationAssistant: z.ZodDefault<z.ZodBoolean>;
369
+ escalation: z.ZodPrefault<z.ZodObject<{
370
+ enabled: z.ZodDefault<z.ZodBoolean>;
371
+ webhookUrl: z.ZodOptional<z.ZodString>;
372
+ }, z.core.$strip>>;
373
+ }, z.core.$strip>>;
374
+ knowledgeBase: z.ZodPrefault<z.ZodObject<{
375
+ enabled: z.ZodDefault<z.ZodBoolean>;
376
+ sources: z.ZodDefault<z.ZodArray<z.ZodObject<{
377
+ url: z.ZodString;
378
+ }, z.core.$strip>>>;
379
+ maxPages: z.ZodDefault<z.ZodNumber>;
380
+ }, z.core.$strip>>;
381
+ }, z.core.$strip>;
272
382
  declare const frankieConfigSchema: z.ZodObject<{
273
383
  tenantId: z.ZodString;
274
384
  branding: z.ZodPrefault<z.ZodObject<{
@@ -368,6 +478,7 @@ declare const frankieConfigSchema: z.ZodObject<{
368
478
  discoveredTools: z.ZodDefault<z.ZodArray<z.ZodObject<{
369
479
  name: z.ZodString;
370
480
  description: z.ZodOptional<z.ZodString>;
481
+ inputs: z.ZodOptional<z.ZodString>;
371
482
  }, z.core.$strip>>>;
372
483
  transport: z.ZodDefault<z.ZodEnum<{
373
484
  http: "http";
@@ -410,6 +521,7 @@ declare const frankieConfigSchema: z.ZodObject<{
410
521
  }>;
411
522
  path: z.ZodString;
412
523
  summary: z.ZodOptional<z.ZodString>;
524
+ inputs: z.ZodOptional<z.ZodString>;
413
525
  authGap: z.ZodDefault<z.ZodBoolean>;
414
526
  }, z.core.$strip>>>;
415
527
  headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -454,12 +566,101 @@ declare const frankieConfigSchema: z.ZodObject<{
454
566
  }, z.core.$strip>>;
455
567
  workspaceAdmin: z.ZodDefault<z.ZodBoolean>;
456
568
  configurationAssistant: z.ZodDefault<z.ZodBoolean>;
569
+ escalation: z.ZodPrefault<z.ZodObject<{
570
+ enabled: z.ZodDefault<z.ZodBoolean>;
571
+ webhookUrl: z.ZodOptional<z.ZodString>;
572
+ }, z.core.$strip>>;
457
573
  }, z.core.$strip>>;
574
+ knowledgeBase: z.ZodPrefault<z.ZodObject<{
575
+ enabled: z.ZodDefault<z.ZodBoolean>;
576
+ sources: z.ZodDefault<z.ZodArray<z.ZodObject<{
577
+ url: z.ZodString;
578
+ }, z.core.$strip>>>;
579
+ maxPages: z.ZodDefault<z.ZodNumber>;
580
+ }, z.core.$strip>>;
581
+ pagePatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
582
+ personas: z.ZodDefault<z.ZodArray<z.ZodObject<{
583
+ id: z.ZodString;
584
+ label: z.ZodString;
585
+ publishableKey: z.ZodString;
586
+ pagePatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
587
+ allowAnonymous: z.ZodOptional<z.ZodBoolean>;
588
+ scope: z.ZodOptional<z.ZodString>;
589
+ contactUrl: z.ZodOptional<z.ZodString>;
590
+ branding: z.ZodOptional<z.ZodObject<{
591
+ name: z.ZodOptional<z.ZodString>;
592
+ tagline: z.ZodOptional<z.ZodString>;
593
+ avatarUrl: z.ZodOptional<z.ZodString>;
594
+ launcherLabel: z.ZodOptional<z.ZodString>;
595
+ }, z.core.$strip>>;
596
+ agent: z.ZodPrefault<z.ZodObject<{
597
+ systemPrompt: z.ZodDefault<z.ZodString>;
598
+ greeting: z.ZodDefault<z.ZodString>;
599
+ suggestedPrompts: z.ZodDefault<z.ZodArray<z.ZodString>>;
600
+ starterPrompts: z.ZodDefault<z.ZodArray<z.ZodObject<{
601
+ title: z.ZodString;
602
+ description: z.ZodOptional<z.ZodString>;
603
+ message: z.ZodString;
604
+ icon: z.ZodOptional<z.ZodEnum<{
605
+ file: "file";
606
+ sparkles: "sparkles";
607
+ wand: "wand";
608
+ book: "book";
609
+ chat: "chat";
610
+ chart: "chart";
611
+ bolt: "bolt";
612
+ music: "music";
613
+ mic: "mic";
614
+ image: "image";
615
+ compass: "compass";
616
+ lightbulb: "lightbulb";
617
+ }>>;
618
+ }, z.core.$strip>>>;
619
+ maxTurns: z.ZodDefault<z.ZodNumber>;
620
+ maxBudgetUsd: z.ZodOptional<z.ZodNumber>;
621
+ tools: z.ZodPrefault<z.ZodObject<{
622
+ allow: z.ZodDefault<z.ZodArray<z.ZodString>>;
623
+ deny: z.ZodDefault<z.ZodArray<z.ZodString>>;
624
+ denyByDefault: z.ZodDefault<z.ZodBoolean>;
625
+ }, z.core.$strip>>;
626
+ showToolActivity: z.ZodDefault<z.ZodBoolean>;
627
+ }, z.core.$strip>>;
628
+ features: z.ZodPrefault<z.ZodObject<{
629
+ attachments: z.ZodPrefault<z.ZodObject<{
630
+ enabled: z.ZodDefault<z.ZodBoolean>;
631
+ accept: z.ZodDefault<z.ZodArray<z.ZodString>>;
632
+ maxMb: z.ZodDefault<z.ZodNumber>;
633
+ maxCount: z.ZodDefault<z.ZodNumber>;
634
+ }, z.core.$strip>>;
635
+ modelPicker: z.ZodPrefault<z.ZodObject<{
636
+ enabled: z.ZodDefault<z.ZodBoolean>;
637
+ models: z.ZodDefault<z.ZodArray<z.ZodObject<{
638
+ id: z.ZodString;
639
+ label: z.ZodString;
640
+ provider: z.ZodOptional<z.ZodString>;
641
+ }, z.core.$strip>>>;
642
+ }, z.core.$strip>>;
643
+ workspaceAdmin: z.ZodDefault<z.ZodBoolean>;
644
+ configurationAssistant: z.ZodDefault<z.ZodBoolean>;
645
+ escalation: z.ZodPrefault<z.ZodObject<{
646
+ enabled: z.ZodDefault<z.ZodBoolean>;
647
+ webhookUrl: z.ZodOptional<z.ZodString>;
648
+ }, z.core.$strip>>;
649
+ }, z.core.$strip>>;
650
+ knowledgeBase: z.ZodPrefault<z.ZodObject<{
651
+ enabled: z.ZodDefault<z.ZodBoolean>;
652
+ sources: z.ZodDefault<z.ZodArray<z.ZodObject<{
653
+ url: z.ZodString;
654
+ }, z.core.$strip>>>;
655
+ maxPages: z.ZodDefault<z.ZodNumber>;
656
+ }, z.core.$strip>>;
657
+ }, z.core.$strip>>>;
458
658
  }, z.core.$strip>;
459
659
  type ThinkingLevel = z.infer<typeof thinkingLevelSchema>;
460
660
  type WidgetThemeConfig = z.infer<typeof widgetThemeSchema>;
461
661
  type ModelChoice = z.infer<typeof modelChoiceSchema>;
462
662
  type FeaturesConfig = z.infer<typeof featuresConfigSchema>;
663
+ type KnowledgeBaseConfig = z.infer<typeof knowledgeBaseSchema>;
463
664
  type ModelConfig = z.infer<typeof modelConfigSchema>;
464
665
  type McpServerConfig = z.infer<typeof mcpServerSchema>;
465
666
  type ApiCapability = z.infer<typeof apiCapabilitySchema>;
@@ -469,11 +670,37 @@ type AgentConfig = z.infer<typeof agentConfigSchema>;
469
670
  type AuthConfig = z.infer<typeof authConfigSchema>;
470
671
  type LimitsConfig = z.infer<typeof limitsConfigSchema>;
471
672
  type BrandingConfig = z.infer<typeof brandingConfigSchema>;
673
+ type PersonaProfile = z.infer<typeof personaProfileSchema>;
472
674
  type FrankieConfig = z.infer<typeof frankieConfigSchema>;
473
675
  type FrankieConfigInput = z.input<typeof frankieConfigSchema>;
474
676
  declare function parseFrankieConfig(input: unknown): FrankieConfig;
475
677
  /** Helper for `frankie.config.ts` files — gives editors full completion. */
476
678
  declare function defineFrankieConfig(config: FrankieConfigInput): FrankieConfigInput;
679
+ /**
680
+ * Flatten a stored config to the single-agent config that a publishable key
681
+ * selects. The base key returns the config unchanged (the primary persona). A
682
+ * persona key returns a config carrying that persona's branding/agent/features/
683
+ * knowledgeBase, its key, and no further personas — so every *resolved* config is
684
+ * still exactly one agent, preserving the one-key-one-agent invariant. An unknown
685
+ * key returns null.
686
+ */
687
+ declare function resolvePersonaConfig(config: FrankieConfig, publishableKey: string): FrankieConfig | null;
688
+ /**
689
+ * A persona's instructions as the agent runs them: its role instructions,
690
+ * then what it helps with and the boundary that follows from it. Off-topic
691
+ * questions get a short "not here" (and a hand-off when the agent escalates)
692
+ * rather than a guess.
693
+ */
694
+ declare function personaInstructions(persona: PersonaProfile): string;
695
+ /**
696
+ * Whether a Next.js `usePathname()` value matches an App-Router path glob:
697
+ * `**` matches any depth (including `/`), `*` matches within one segment, and a
698
+ * trailing `/**` also matches the base path itself (`/docs/**` matches `/docs`).
699
+ * Everything else is literal and case-sensitive.
700
+ */
701
+ declare function matchesPagePattern(pathname: string, pattern: string): boolean;
702
+ /** True when `pathname` matches any pattern, or when there are none (host decides). */
703
+ declare function matchesAnyPagePattern(pathname: string, patterns: readonly string[]): boolean;
477
704
 
478
705
  /**
479
706
  * The wire protocol between the embedded widget and the Frankie server.
@@ -686,6 +913,8 @@ interface PublicWidgetConfig {
686
913
  showToolActivity: boolean;
687
914
  /** Opt-in capabilities the widget should render (attachments, model picker). */
688
915
  features: PublicFeatures;
916
+ /** App-Router path globs this agent shows on; empty = every page no other agent claims. Optional so older servers stay compatible. */
917
+ pages?: string[];
689
918
  }
690
919
  /** The subset of `features` config the widget needs to render its controls. */
691
920
  interface PublicFeatures {
@@ -747,6 +976,38 @@ declare const SKILL_TOOL_NAME = "frankie__use_skill";
747
976
  /** A short human label for a tool call, for the "Frankie is …" line in the UI. */
748
977
  declare function describeTool(toolName: string, input: unknown): string;
749
978
 
979
+ /** The public env var a persona's publishable key lives in. */
980
+ declare function personaEnvKey(personaId: string): string;
981
+ /**
982
+ * The agents every generated mount lists, ahead of the workspace's own custom
983
+ * ones. Listing them even before they exist means turning one on later is an
984
+ * environment variable, not another pull request.
985
+ */
986
+ declare const STANDARD_AGENT_IDS: readonly ["support", "docs"];
987
+ /** The persona ids a generated mount lists, in priority order: the standard ones, then custom ones alphabetically. */
988
+ declare function installAgentIds(personaIds?: string[]): string[];
989
+ /**
990
+ * The install branch for a workspace, or one of its personas. One commit,
991
+ * `<sha8>`-suffixed so a re-run on a new base opens a fresh PR. A persona is
992
+ * joined with `--` so workspace `acme` + persona `support` never shares a
993
+ * branch with workspace `acme-support`.
994
+ */
995
+ declare function installBranch(workspaceId: string, baseSha: string, personaId?: string): string;
996
+ /**
997
+ * A workspace-supplied name (workspace, agent label, page pattern) made safe
998
+ * to drop into a PR body or committed Markdown: one line, no markup that
999
+ * could add links, images, code or headings under the installer's name.
1000
+ */
1001
+ declare function plainText(value: string, max?: number): string;
1002
+ /** The install PR title: plain for the primary agent, suffixed with the persona's label otherwise. */
1003
+ declare function installTitle(personaLabel?: string): string;
1004
+ /**
1005
+ * Whether an open PR's head ref is the install branch for this
1006
+ * workspace/persona — used to adopt a PR a prior run opened. The anchored
1007
+ * 8-hex suffix keeps a persona branch from matching the primary and vice
1008
+ * versa; a persona also matches the older single-dash form.
1009
+ */
1010
+ declare function matchesInstallBranch(ref: string, workspaceId: string, personaId?: string): boolean;
750
1011
  /** One installation plan for GitHub and the local CLI. Never includes credentials. */
751
1012
  interface InstallProject {
752
1013
  files: Record<string, string>;
@@ -757,12 +1018,31 @@ interface InstallProject {
757
1018
  allowAnonymous: boolean;
758
1019
  };
759
1020
  apiBaseUrl?: string;
1021
+ /**
1022
+ * The agent this PR is for, when it is a persona (Support, Docs, a custom
1023
+ * one) rather than the product agent. It only changes what else the PR
1024
+ * carries: every PR writes the same `FrankieAgents` mount, so a persona PR
1025
+ * and a product PR opened together never conflict. The key stays in the
1026
+ * environment, never here.
1027
+ */
1028
+ persona?: {
1029
+ id: string;
1030
+ label: string;
1031
+ publishableKey?: string;
1032
+ pagePatterns?: string[];
1033
+ envKey?: string;
1034
+ };
1035
+ /** Every persona id on the workspace, so the mount lists the custom ones too. */
1036
+ agents?: string[];
760
1037
  }
761
1038
  interface InstallPlan {
1039
+ /** Files to write. Files whose content would not change are left out. */
762
1040
  files: Array<{
763
1041
  path: string;
764
1042
  content: string;
765
1043
  }>;
1044
+ /** Frankie's own superseded files to remove. */
1045
+ deletions: string[];
766
1046
  root: string;
767
1047
  chatPath: string;
768
1048
  specPath: string;
@@ -776,9 +1056,52 @@ declare function assertNoCommittedFrankieKeys(files: Array<{
776
1056
  path: string;
777
1057
  content: string;
778
1058
  }>): void;
1059
+ /**
1060
+ * Plan the files for an install PR.
1061
+ *
1062
+ * Every agent (product, support, docs, custom) mounts from one generated
1063
+ * client component, `<app>/frankie/FrankieAgents.tsx`, rendered once in the
1064
+ * root layout. It lists each agent by its own env var, turns an agent on only
1065
+ * when that key is set, and reads each agent's pages from `/v1/config` at
1066
+ * runtime. Its content depends only on the repository and the workspace — not
1067
+ * on which agent the PR is for — so the shared files (mount, layout edit,
1068
+ * package.json, .env.example, health route) are byte-identical in every PR,
1069
+ * and any two install PRs merge cleanly in either order.
1070
+ */
779
1071
  declare function planHostedInstall(input: InstallProject): InstallPlan;
780
1072
  /** Where the generated token endpoint gets the signed-in user from. */
781
1073
  type AuthStrategy = "firebase" | "nextauth" | "supabase" | "custom" | "existing" | "anonymous" | "unconfigured";
1074
+ /**
1075
+ * Where a new import may go in a module: after the directive prologue, any
1076
+ * leading comments and the existing imports (multi-line ones included), and
1077
+ * never above a `"use client"`. A directive is only a directive while it is the
1078
+ * first statement — an import placed ahead of it turns it into a no-op string,
1079
+ * and the layout silently stops being a client component.
1080
+ */
1081
+ declare function insertImport(source: string, importLine: string): string;
1082
+ /**
1083
+ * Adds `<FrankieWidgetMount />` (or another component) just inside the layout's `</body>` (else
1084
+ * `</main>`, else after `{children}`), indented like the line it joins so the
1085
+ * change is one clean line in the PR and a formatter check does not fail on it.
1086
+ */
1087
+ declare function mountWidget(layout: string, component?: string): string | undefined;
1088
+ /**
1089
+ * The manifest's dependencies with Frankie's added — keeping an entry the
1090
+ * project already pins, and keeping alphabetical order when the project keeps
1091
+ * it (as npm and pnpm write it), so the PR's diff is the added lines only.
1092
+ */
1093
+ declare function withDependencies(current: Record<string, string> | undefined, added: Record<string, string>): Record<string, string>;
1094
+ /** JSON written the way the file already was: its indentation (tabs or spaces) and its final newline. */
1095
+ declare function renderJson(value: unknown, original: string | undefined): string;
1096
+ /**
1097
+ * How a generated file imports a module under the app's source root
1098
+ * (`lib/frankie-auth`, `auth`, …). The repo's own `tsconfig.json` decides:
1099
+ * whichever `paths` alias maps onto the source root is used (`@/`, `~/`,
1100
+ * `@src/`…); with a tsconfig that declares no such alias the import is
1101
+ * relative, which resolves everywhere. Without a tsconfig to read, `@/` stands —
1102
+ * Next.js's own default — rather than a guess at a relative layout.
1103
+ */
1104
+ declare function moduleImporter(files: Record<string, string>, root: string, sourceRoot: string): (fromFile: string, module: string) => string;
782
1105
 
783
1106
  declare const skillSchema: z.ZodObject<{
784
1107
  id: z.ZodString;
@@ -809,6 +1132,7 @@ declare function approvedSkillTools(config: FrankieConfig): string[];
809
1132
  declare function toolDescriptions(config: FrankieConfig, toolIds: string[]): Array<{
810
1133
  id: string;
811
1134
  description: string;
1135
+ inputs?: string;
812
1136
  }>;
813
1137
  /**
814
1138
  * Starter suggestion prompts derived from the workspace's own published,
@@ -826,7 +1150,7 @@ declare function suggestedPromptsFromSkills(config: FrankieConfig): string[];
826
1150
  /**
827
1151
  * Deterministic starter for the manual editor — not a claim that anything
828
1152
  * was executed, and not model-generated. Follows the same structure asked of
829
- * AI-generated instructions (trigger recap, required inputs, numbered steps,
1153
+ * AI-generated instructions (trigger recap, required inputs, quality bar, numbered steps,
830
1154
  * reporting, error handling) so a hand-written skill starts from a useful
831
1155
  * shape instead of a blank textarea. `label` is each tool's own description
832
1156
  * when the caller has one (e.g. from the dashboard's approved-tools list);
@@ -865,4 +1189,38 @@ declare function compareApiDocuments(before: ApiDocument, after: ApiDocument): {
865
1189
  unchangedIds: string[];
866
1190
  };
867
1191
 
868
- export { type AgentConfig, type ApiCapability, type ApiDocument, type ApiSourceConfig, type ApiToolInventory, type AuthConfig, type AuthStrategy, type BrandingConfig, type ChatAttachment, type ChatRequestBody, type CreateSessionBody, type CreateSessionResponse, FIREWORKS_MODELS, type FeaturesConfig, type FrankieConfig, type FrankieConfigInput, type FrankieErrorCode, type FrankieServerEvent, type HostToolRequest, type HostToolResult, type InstallPlan, type InstallProject, type LimitsConfig, type LoadedSkill, type McpServerConfig, type ModelChoice, type ModelConfig, type PublicFeatures, type PublicWidgetConfig, SKILL_TOOL_NAME, STARTER_PROMPT_ICONS, type StarterPrompt, type StarterPromptIcon, type StopReason, type ThinkingLevel, type ToolDecision, type ToolPolicy, type ToolResultBody, type UsageSummary, type WidgetTheme, type WidgetThemeConfig, type WorkspaceSkill, activeSkills, agentConfigSchema, apiCapabilitySchema, apiMethods, apiOperations, apiSourceSchema, approvedSkillTools, assertNoCommittedFrankieKeys, authConfigSchema, brandingConfigSchema, canonicalJson, compareApiDocuments, defineFrankieConfig, describeTool, draftSkill, evaluateToolPolicy, featuresConfigSchema, frankieConfigSchema, limitsConfigSchema, matchPath, mcpServerSchema, modelChoiceSchema, modelConfigSchema, operationId, parseFrankieConfig, planHostedInstall, sdkUpdateWorkflow, skillSchema, starterPromptSchema, suggestedPromptsFromSkills, thinkingLevelSchema, toolDescriptions, toolPolicySchema, validateApiDocument, widgetThemeSchema };
1192
+ /**
1193
+ * Suggest a widget theme from a repository's own styling, at install time.
1194
+ *
1195
+ * Reads what a Next.js app already declares — CSS custom properties on `:root`
1196
+ * (shadcn/ui, Tailwind v4 `@theme`), the Tailwind config's colors, the
1197
+ * `themeColor` metadata and the web app manifest — and normalizes the colors it
1198
+ * can read to `#rrggbb`. Like the rest of the installer it is regex over source:
1199
+ * nothing is executed, and anything it can't read with confidence is left out
1200
+ * rather than guessed. The result is a *suggestion* the dashboard asks the user
1201
+ * to accept; it never replaces a theme someone chose.
1202
+ */
1203
+ interface InferredTheme {
1204
+ /** Always carries a brand color: without one there is nothing to suggest. */
1205
+ theme: {
1206
+ primary: string;
1207
+ background?: string;
1208
+ foreground?: string;
1209
+ radius?: string;
1210
+ };
1211
+ /** Where each value came from, for the "suggested from your repo" explanation. */
1212
+ sources: Array<{
1213
+ field: "primary" | "background" | "foreground" | "radius";
1214
+ path: string;
1215
+ }>;
1216
+ }
1217
+ /** Normalize a CSS color to `#rrggbb`, or undefined when it isn't one we can read confidently. */
1218
+ declare function normalizeColor(raw: string): string | undefined;
1219
+ /**
1220
+ * Infer a theme from repository files (path → content). `root` scopes the search
1221
+ * to one app in a monorepo ("" for the repository root). Returns undefined when
1222
+ * no brand color can be read — a background alone is not a theme.
1223
+ */
1224
+ declare function inferTheme(files: Record<string, string>, root?: string): InferredTheme | undefined;
1225
+
1226
+ export { type AgentConfig, type ApiCapability, type ApiDocument, type ApiSourceConfig, type ApiToolInventory, type AuthConfig, type AuthStrategy, type BrandingConfig, type ChatAttachment, type ChatRequestBody, type CreateSessionBody, type CreateSessionResponse, FIREWORKS_MODELS, type FeaturesConfig, type FrankieConfig, type FrankieConfigInput, type FrankieErrorCode, type FrankieServerEvent, type HostToolRequest, type HostToolResult, type InferredTheme, type InstallPlan, type InstallProject, type KnowledgeBaseConfig, type LimitsConfig, type LoadedSkill, type McpServerConfig, type ModelChoice, type ModelConfig, type PersonaProfile, type PublicFeatures, type PublicWidgetConfig, SKILL_TOOL_NAME, STANDARD_AGENT_IDS, STARTER_PROMPT_ICONS, type StarterPrompt, type StarterPromptIcon, type StopReason, type ThinkingLevel, type ToolDecision, type ToolPolicy, type ToolResultBody, type UsageSummary, type WidgetTheme, type WidgetThemeConfig, type WorkspaceSkill, activeSkills, agentConfigSchema, apiCapabilitySchema, apiMethods, apiOperations, apiSourceSchema, approvedSkillTools, assertNoCommittedFrankieKeys, authConfigSchema, brandingConfigSchema, canonicalJson, compareApiDocuments, defineFrankieConfig, describeTool, draftSkill, evaluateToolPolicy, featuresConfigSchema, frankieConfigSchema, inferTheme, insertImport, installAgentIds, installBranch, installTitle, knowledgeBaseSchema, knowledgeSourceSchema, limitsConfigSchema, matchPath, matchesAnyPagePattern, matchesInstallBranch, matchesPagePattern, mcpServerSchema, modelChoiceSchema, modelConfigSchema, moduleImporter, mountWidget, normalizeColor, operationId, parseFrankieConfig, personaEnvKey, personaInstructions, personaProfileSchema, plainText, planHostedInstall, renderJson, resolvePersonaConfig, sdkUpdateWorkflow, skillSchema, starterPromptSchema, suggestedPromptsFromSkills, thinkingLevelSchema, toolDescriptions, toolPolicySchema, validateApiDocument, widgetThemeSchema, withDependencies };