@actioneer/ads 0.2.2 → 0.2.3

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/bin/ads-init.mjs CHANGED
@@ -12,8 +12,10 @@
12
12
  * • inject `@import "@actioneer/ads/styles.css";` right after
13
13
  * `@import "tailwindcss";` in the global stylesheet
14
14
  * • scaffold the three required providers (TooltipProvider, ToastProvider,
15
- * <MotionConfig reducedMotion="user">) as `app/providers.tsx` and wrap the
16
- * root layout's children with them
15
+ * <MotionConfig reducedMotion="user">) into a CLI-OWNED `ads-providers.{tsx,jsx}`
16
+ * (never the user's own `providers.*` — see the overwrite-safety guard) and
17
+ * wrap the root layout's children with them. The file extension + whether it
18
+ * carries TS type annotations follow the project language (TS vs JS).
17
19
  * • drop a consumer-mode `ads-lint.config.mjs`
18
20
  * (`libraryPackage: "@actioneer/ads"`, `libraryRoot: null`)
19
21
  *
@@ -40,6 +42,7 @@ const STYLE_IMPORT = `@import "${PKG}/styles.css";`;
40
42
  * @property {string|null} layoutPath repo-relative path to the root layout (or null)
41
43
  * @property {string|null} layoutContent
42
44
  * @property {boolean} hasAdsLintConfig
45
+ * @property {"ts"|"js"} [language] consumer project language (default "ts")
43
46
  * @property {"npm"|"pnpm"|"yarn"|"bun"} [packageManager] detected consumer PM (default npm)
44
47
  *
45
48
  * @typedef {Object} Edit
@@ -132,16 +135,21 @@ export function planInit(state) {
132
135
  });
133
136
  }
134
137
 
135
- // 3. Scaffold the providers file + wrap the layout.
138
+ // 3. Scaffold the CLI-OWNED providers file + wrap the layout.
139
+ // We write `ads-providers.{tsx,jsx}` (NOT `providers.*`) so a consumer's own
140
+ // `providers.tsx` is never touched or trusted, and the layout imports
141
+ // { Providers } from OUR file. Extension + TS annotations follow the language.
142
+ const language = state.language === "js" ? "js" : "ts";
143
+ const providersBasename = language === "js" ? "ads-providers.jsx" : "ads-providers.tsx";
136
144
  if (state.layoutPath != null) {
137
145
  const dir = path.posix.dirname(toPosix(state.layoutPath));
138
- const providersPath = path.posix.join(dir, "providers.tsx");
146
+ const providersPath = path.posix.join(dir, providersBasename);
139
147
  if (!fileExistsInState(state, providersPath)) {
140
148
  edits.push({
141
149
  type: "write-file",
142
150
  title: `scaffold providers at ${providersPath}`,
143
151
  path: providersPath,
144
- content: PROVIDERS_FILE,
152
+ content: providersFile(language),
145
153
  });
146
154
  }
147
155
  if (state.layoutContent != null && !state.layoutContent.includes("<Providers>")) {
@@ -154,25 +162,25 @@ export function planInit(state) {
154
162
  find: child,
155
163
  findIndex: state.layoutContent.indexOf(child, state.layoutContent.indexOf("return")),
156
164
  replace: `<Providers>${child}</Providers>`,
157
- addImport: `import { Providers } from "./providers";`,
165
+ addImport: `import { Providers } from "./ads-providers";`,
158
166
  });
159
167
  } else {
160
168
  edits.push({
161
169
  type: "manual",
162
- title: `wrap your app root's children with <Providers> (from ./providers)`,
170
+ title: `wrap your app root's children with <Providers> (from ./ads-providers)`,
163
171
  });
164
172
  }
165
173
  }
166
174
  } else {
167
175
  edits.push({
168
176
  type: "write-file",
169
- title: "scaffold providers at app/providers.tsx",
170
- path: "app/providers.tsx",
171
- content: PROVIDERS_FILE,
177
+ title: `scaffold providers at app/${providersBasename}`,
178
+ path: `app/${providersBasename}`,
179
+ content: providersFile(language),
172
180
  });
173
181
  edits.push({
174
182
  type: "manual",
175
- title: "wrap your app root's children with <Providers> (from ./providers)",
183
+ title: "wrap your app root's children with <Providers> (from ./ads-providers)",
176
184
  });
177
185
  }
178
186
 
@@ -212,7 +220,18 @@ export function findJsxChildren(source) {
212
220
  return null;
213
221
  }
214
222
 
215
- const PROVIDERS_FILE = `"use client";
223
+ /**
224
+ * The ADS providers scaffold, generated for the consumer's language. A TS project
225
+ * gets the typed signature; a JS project gets a plain signature with NO TypeScript
226
+ * annotations (a `: { children: React.ReactNode }` in a `.jsx`/`.js` file is a
227
+ * syntax error). The file extension is chosen by the caller (`ads-providers.tsx`
228
+ * vs `ads-providers.jsx`).
229
+ * @param {"ts"|"js"} language
230
+ */
231
+ export function providersFile(language) {
232
+ const signature =
233
+ language === "js" ? "{ children }" : "{ children }: { children: React.ReactNode }";
234
+ return `"use client";
216
235
 
217
236
  // Required ADS providers — wrap the app root once. Without TooltipProvider the
218
237
  // vendored tooltip/attachment chips crash; ToastProvider is needed to render
@@ -220,7 +239,7 @@ const PROVIDERS_FILE = `"use client";
220
239
  import { TooltipProvider, ToastProvider } from "${PKG}";
221
240
  import { MotionConfig } from "motion/react";
222
241
 
223
- export function Providers({ children }: { children: React.ReactNode }) {
242
+ export function Providers(${signature}) {
224
243
  return (
225
244
  <MotionConfig reducedMotion="user">
226
245
  <ToastProvider>
@@ -230,6 +249,63 @@ export function Providers({ children }: { children: React.ReactNode }) {
230
249
  );
231
250
  }
232
251
  `;
252
+ }
253
+
254
+ /**
255
+ * Detect the consumer project's language. The chosen root layout's extension is
256
+ * the most authoritative signal (`.tsx`/`.ts` → TS, `.jsx`/`.js` → JS); with no
257
+ * layout, presence of a tsconfig.json decides, defaulting to JS. Drives whether
258
+ * the scaffolded providers file is `.tsx` (typed) or `.jsx` (untyped).
259
+ * @param {{layoutPath?:string|null, hasTsconfig?:boolean}} [signals]
260
+ * @returns {"ts"|"js"}
261
+ */
262
+ export function detectLanguage({ layoutPath, hasTsconfig } = {}) {
263
+ if (layoutPath) {
264
+ if (/\.tsx?$/.test(layoutPath)) return "ts";
265
+ if (/\.jsx?$/.test(layoutPath)) return "js";
266
+ }
267
+ return hasTsconfig ? "ts" : "js";
268
+ }
269
+
270
+ /**
271
+ * Insert an import line into module source, DIRECTIVE-AWARE. If the file opens
272
+ * with a directive prologue (`"use client"` / `'use server'` / `"use strict"`,
273
+ * possibly after leading comments/blank lines), the import lands AFTER the last
274
+ * such directive so the directive stays the first statement — otherwise Next
275
+ * treats a `"use client"` layout as a Server Component and `next build` breaks.
276
+ * With no directive, the import prepends to the very top. Idempotent.
277
+ */
278
+ export function insertImport(content, importLine) {
279
+ if (content.includes(importLine)) return content;
280
+ const lines = content.split("\n");
281
+ const directiveRe = /^(["'])use [\w-]+\1\s*;?$/;
282
+ let i = 0;
283
+ let insertAt = 0; // default: the very top
284
+ while (i < lines.length) {
285
+ const trimmed = lines[i].trim();
286
+ if (trimmed === "") {
287
+ i++;
288
+ continue;
289
+ }
290
+ if (trimmed.startsWith("//")) {
291
+ i++;
292
+ continue;
293
+ }
294
+ if (trimmed.startsWith("/*")) {
295
+ while (i < lines.length && !lines[i].includes("*/")) i++;
296
+ if (i < lines.length) i++; // consume the closing line
297
+ continue;
298
+ }
299
+ if (directiveRe.test(trimmed)) {
300
+ i++;
301
+ insertAt = i; // land after this (the last-seen) directive
302
+ continue;
303
+ }
304
+ break; // first real code line — stop scanning
305
+ }
306
+ lines.splice(insertAt, 0, importLine);
307
+ return lines.join("\n");
308
+ }
233
309
 
234
310
  const ADS_LINT_CONFIG = `// @actioneer/ads-lint — consumer mode. Every file is a consumer, so the
235
311
  // barrel / deep-import / external-UI rules apply everywhere. See the ADS
@@ -252,7 +328,22 @@ const CANDIDATE_CSS = [
252
328
  "app/global.css",
253
329
  "src/styles/globals.css",
254
330
  ];
255
- const CANDIDATE_LAYOUT = ["app/layout.tsx", "src/app/layout.tsx", "app/layout.jsx", "src/app/layout.jsx"];
331
+ // `create-next-app` emits `app/layout.js` for a JS project and `app/layout.tsx`
332
+ // for TS, under `app/` or `src/app/`. All six must be recognized or a fresh JS
333
+ // repo is never bootstrapped (#3).
334
+ const CANDIDATE_LAYOUT = [
335
+ "app/layout.tsx",
336
+ "src/app/layout.tsx",
337
+ "app/layout.jsx",
338
+ "src/app/layout.jsx",
339
+ "app/layout.js",
340
+ "src/app/layout.js",
341
+ ];
342
+
343
+ /** The chosen root layout among the conventional locations (or null). */
344
+ function detectLayoutPath(cwd) {
345
+ return CANDIDATE_LAYOUT.find((p) => fs.existsSync(path.join(cwd, p))) ?? null;
346
+ }
256
347
 
257
348
  // The load-bearing anchor: ADS styles must import into the SAME CSS graph as
258
349
  // tailwindcss, right after it (styles.css before tailwindcss leaves @theme
@@ -271,20 +362,53 @@ function fileExistsInState(state, relPosix) {
271
362
  }
272
363
 
273
364
  /**
274
- * Find the global stylesheet to wire ADS styles into. Because the import order
275
- * is load-bearing, detection PREFERS the stylesheet that already imports
276
- * tailwindcss — first among the conventional locations, then ANYWHERE in the
277
- * project (bounded scan) so a non-standard path (e.g. `src/index.css`,
278
- * `app/tailwind.css`) is auto-wired instead of degrading to a hand-edit note.
279
- * Falls back to the first conventional file that exists (→ manual, with anchor
280
- * guidance), else null.
365
+ * Find the global stylesheet to wire ADS styles into. Detection is BOUND TO THE
366
+ * SELECTED LAYOUT first (#8): the stylesheet the chosen root layout actually
367
+ * imports (or one adjacent to it) is the sheet that loads, so a stale
368
+ * `app/globals.css` can't get the ADS import while the real `src/app/...` layout
369
+ * imports a different sheet. Only when the layout yields nothing do we fall back
370
+ * to the flat scan. Because the import order is load-bearing, each tier PREFERS
371
+ * the stylesheet that already imports tailwindcss — the conventional locations,
372
+ * then ANYWHERE in the project (bounded scan) so a non-standard path (e.g.
373
+ * `src/index.css`, `app/tailwind.css`) is auto-wired instead of degrading to a
374
+ * hand-edit note. Falls back to the first conventional file that exists (→ manual,
375
+ * with anchor guidance), else null.
376
+ * @param {string} cwd
377
+ * @param {string|null} [layoutPath] the selected root layout (repo-relative), to bind CSS discovery to
281
378
  * @returns {{path: string|null, content: string|null}}
282
379
  */
283
- export function detectGlobalCss(cwd) {
380
+ export function detectGlobalCss(cwd, layoutPath = null) {
284
381
  const read = (rel) => {
285
382
  const abs = path.join(cwd, rel);
286
383
  return fs.existsSync(abs) ? fs.readFileSync(abs, "utf8") : null;
287
384
  };
385
+
386
+ // 0. Layout-anchored: the stylesheet the SELECTED layout imports (resolved
387
+ // relative to the layout dir), or a globals.css adjacent to it.
388
+ if (layoutPath) {
389
+ const layoutContent = read(layoutPath);
390
+ const layoutDir = path.posix.dirname(toPosix(layoutPath));
391
+ if (layoutContent != null) {
392
+ let firstImported = null;
393
+ for (const m of layoutContent.matchAll(/import\s+["']([^"']+\.css)["']/g)) {
394
+ const spec = m[1];
395
+ if (!spec.startsWith(".")) continue; // skip package/alias CSS imports
396
+ const rel = toPosix(path.posix.normalize(path.posix.join(layoutDir, spec)));
397
+ const c = read(rel);
398
+ if (c == null) continue;
399
+ if (firstImported == null) firstImported = { path: rel, content: c };
400
+ if (TAILWIND_IMPORT_RE.test(c)) return { path: rel, content: c }; // anchored sheet wins
401
+ }
402
+ if (firstImported) return firstImported; // the sheet the layout loads, even w/o anchor
403
+ }
404
+ // A conventional stylesheet sitting next to the layout.
405
+ for (const name of ["globals.css", "global.css"]) {
406
+ const rel = path.posix.join(layoutDir, name);
407
+ const c = read(rel);
408
+ if (c != null) return { path: rel, content: c };
409
+ }
410
+ }
411
+
288
412
  // 1. Conventional location that already imports tailwindcss (the anchor).
289
413
  for (const p of CANDIDATE_CSS) {
290
414
  const c = read(p);
@@ -341,7 +465,7 @@ function scanForTailwindCss(cwd, maxDepth = 5) {
341
465
  * @returns {{ok: boolean, path: string|null}}
342
466
  */
343
467
  export function verifyStylesWired(cwd) {
344
- const css = detectGlobalCss(cwd);
468
+ const css = detectGlobalCss(cwd, detectLayoutPath(cwd));
345
469
  return { ok: css.content != null && css.content.includes(STYLE_IMPORT), path: css.path };
346
470
  }
347
471
 
@@ -360,11 +484,24 @@ function readRepoState(cwd) {
360
484
  lockfiles: LOCKFILES.filter((f) => fs.existsSync(path.join(cwd, f))),
361
485
  });
362
486
 
363
- const css = detectGlobalCss(cwd);
364
- const layoutPath = CANDIDATE_LAYOUT.find((p) => fs.existsSync(path.join(cwd, p))) ?? null;
365
-
487
+ // Detect the layout FIRST — both CSS discovery (#8) and language detection (#3)
488
+ // key off it.
489
+ const layoutPath = detectLayoutPath(cwd);
490
+ const language = detectLanguage({
491
+ layoutPath,
492
+ hasTsconfig: fs.existsSync(path.join(cwd, "tsconfig.json")),
493
+ });
494
+ const css = detectGlobalCss(cwd, layoutPath);
495
+
496
+ // Existence set: the CLI-owned providers file lives next to the layout, in the
497
+ // language-matched extension — track both so a re-run is a no-op.
498
+ const providersDir = layoutPath ? path.posix.dirname(toPosix(layoutPath)) : "app";
499
+ const providersCandidates = [
500
+ path.posix.join(providersDir, "ads-providers.tsx"),
501
+ path.posix.join(providersDir, "ads-providers.jsx"),
502
+ ];
366
503
  const _existing = new Set();
367
- for (const p of [...CANDIDATE_CSS, ...CANDIDATE_LAYOUT, "ads-lint.config.mjs", "app/providers.tsx", "src/app/providers.tsx"]) {
504
+ for (const p of [...CANDIDATE_CSS, ...CANDIDATE_LAYOUT, "ads-lint.config.mjs", ...providersCandidates]) {
368
505
  if (fs.existsSync(path.join(cwd, p))) _existing.add(p);
369
506
  }
370
507
 
@@ -376,6 +513,7 @@ function readRepoState(cwd) {
376
513
  layoutContent: layoutPath ? read(layoutPath) : null,
377
514
  hasAdsLintConfig:
378
515
  fs.existsSync(path.join(cwd, "ads-lint.config.mjs")) || fs.existsSync(path.join(cwd, "ads-lint.config.js")),
516
+ language,
379
517
  packageManager,
380
518
  _existing,
381
519
  };
@@ -391,6 +529,13 @@ function applyEdit(cwd, edit) {
391
529
  return;
392
530
  }
393
531
  case "write-file": {
532
+ // NEVER overwrite an existing file (#4): an existing source file — even the
533
+ // CLI-owned providers name — is left untouched and reported, so init can
534
+ // never destroy user content.
535
+ if (fs.existsSync(abs)) {
536
+ console.log(` → skipped ${edit.path} (already exists — left untouched)`);
537
+ return;
538
+ }
394
539
  fs.mkdirSync(path.dirname(abs), { recursive: true });
395
540
  fs.writeFileSync(abs, edit.content);
396
541
  console.log(` → wrote ${edit.path}`);
@@ -408,7 +553,10 @@ function applyEdit(cwd, edit) {
408
553
  } else {
409
554
  content = content.replace(edit.find, edit.replace);
410
555
  }
411
- if (edit.addImport && !content.includes(edit.addImport)) content = `${edit.addImport}\n${content}`;
556
+ // Directive-aware (#5): insert the import AFTER any leading `"use client"`
557
+ // prologue so the directive stays first and `next build` keeps the layout a
558
+ // Client Component.
559
+ if (edit.addImport) content = insertImport(content, edit.addImport);
412
560
  fs.writeFileSync(abs, content);
413
561
  console.log(` → edited ${edit.path}`);
414
562
  return;
package/llms.txt CHANGED
@@ -253,8 +253,6 @@ ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+);
253
253
 
254
254
  - [Accordion] — Use for FAQ-style or settings-style stacked content where headings should collapse to save space and only the relevant section needs to be visible at once. [docs](https://ads.actioneer.dev/#/accordion)
255
255
  - [AccordionItem] — component [docs](https://ads.actioneer.dev/#/accordion)
256
- - [ANSWER_TOOL_DESCRIPTION] — component (variants: tone: default|primary|success|warning|danger|info) [docs](https://ads.actioneer.dev/#/ai/answer)
257
- - [ANSWER_TOOL_NAME] — component (variants: tone: default|primary|success|warning|danger|info) [docs](https://ads.actioneer.dev/#/ai/answer)
258
256
  - [AnswerRenderer] — component (variants: tone: default|primary|success|warning|danger|info) [docs](https://ads.actioneer.dev/#/ai/answer)
259
257
  - [AreaChart] — component [docs](https://ads.actioneer.dev/#/chart)
260
258
  - [Avatar] — Use to represent a person or entity as a compact photo-or-initials glyph, standalone or stacked in an AvatarGroup. [docs](https://ads.actioneer.dev/#/avatar)
@@ -371,6 +369,8 @@ ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+);
371
369
  - [TreemapDatum] — TypeScript type
372
370
  - [TrendAnswerProps] — TypeScript type
373
371
  - [TrendAnswerSpec] — TypeScript type
372
+ - [ANSWER_TOOL_DESCRIPTION] — utility
373
+ - [ANSWER_TOOL_NAME] — utility
374
374
  - [AnswerFollowUpSchema] — utility
375
375
  - [AnswerSignalSchema] — utility
376
376
  - [AnswerSourceSchema] — utility
@@ -526,9 +526,6 @@ ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+);
526
526
  - [ToolInput] — component [docs](https://ads.actioneer.dev/#/ai/tool)
527
527
  - [ToolOutput] — component [docs](https://ads.actioneer.dev/#/ai/tool)
528
528
  - [Voice] — component [docs](https://ads.actioneer.dev/#/ai/voice)
529
- - [VOICE_PALETTES] — component [docs](https://ads.actioneer.dev/#/ai/voice)
530
- - [VOICE_STATES] — component [docs](https://ads.actioneer.dev/#/ai/voice)
531
- - [VOICE_VARIANTS] — component [docs](https://ads.actioneer.dev/#/ai/voice)
532
529
  - [VoiceConnectButton] — component [docs](https://ads.actioneer.dev/#/ai/voice)
533
530
  - [VoiceControl] — component [docs](https://ads.actioneer.dev/#/ai/voice)
534
531
  - [VoiceDisconnectButton] — component [docs](https://ads.actioneer.dev/#/ai/voice)
@@ -622,10 +619,12 @@ ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+);
622
619
  - [VoiceVariant] — TypeScript type
623
620
  - [useReasoning] — React hook
624
621
  - [Tool] — utility
622
+ - [VOICE_PALETTES] — utility
623
+ - [VOICE_STATES] — utility
624
+ - [VOICE_VARIANTS] — utility
625
625
 
626
626
  ### Chat
627
627
 
628
- - [ACTIONEER_FILE_ACCEPT] — component [docs](https://ads.actioneer.dev/#/demo/ask)
629
628
  - [AssistantActionBar] — component [docs](https://ads.actioneer.dev/#/demo/ask)
630
629
  - [AssistantMessage] — component [docs](https://ads.actioneer.dev/#/demo/ask)
631
630
  - [AssistantRuntimeProvider] — component [docs](https://ads.actioneer.dev/#/demo/ask)
@@ -647,11 +646,9 @@ ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+);
647
646
  - [ComposerQuotePreviewRoot] — component [docs](https://ads.actioneer.dev/#/demo/ask)
648
647
  - [ComposerQuotePreviewText] — component [docs](https://ads.actioneer.dev/#/demo/ask)
649
648
  - [ComposerTriggerPopover] — component [docs](https://ads.actioneer.dev/#/demo/ask)
650
- - [CONTEXT_MIME] — component [docs](https://ads.actioneer.dev/#/demo/ask)
651
649
  - [DeepResearchProvider] — component [docs](https://ads.actioneer.dev/#/demo/ask)
652
650
  - [DirectiveText] — component [docs](https://ads.actioneer.dev/#/demo/ask)
653
651
  - [EditComposer] — component [docs](https://ads.actioneer.dev/#/demo/ask)
654
- - [EMPTY_COMPONENTS] — component [docs](https://ads.actioneer.dev/#/demo/ask)
655
652
  - [ErrorRoot] — component [docs](https://ads.actioneer.dev/#/demo/ask)
656
653
  - [ErrorText] — component [docs](https://ads.actioneer.dev/#/demo/ask)
657
654
  - [File] — component [docs](https://ads.actioneer.dev/#/demo/ask)
@@ -661,7 +658,6 @@ ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+);
661
658
  - [FileRoot] — component [docs](https://ads.actioneer.dev/#/demo/ask)
662
659
  - [FileSize] — component [docs](https://ads.actioneer.dev/#/demo/ask)
663
660
  - [FollowUpSuggestion] — component [docs](https://ads.actioneer.dev/#/demo/ask)
664
- - [HARNESS_MIME] — component [docs](https://ads.actioneer.dev/#/demo/ask)
665
661
  - [Image] — component [docs](https://ads.actioneer.dev/#/demo/ask)
666
662
  - [ImageActions] — component [docs](https://ads.actioneer.dev/#/demo/ask)
667
663
  - [ImageContentFilterError] — component [docs](https://ads.actioneer.dev/#/demo/ask)
@@ -734,15 +730,19 @@ ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+);
734
730
  - [useAssistantRuntime] — React hook
735
731
  - [useAuiState] — React hook
736
732
  - [useLocalRuntime] — React hook
733
+ - [ACTIONEER_FILE_ACCEPT] — utility
737
734
  - [ActioneerFileAttachmentAdapter] — utility
738
735
  - [ComposerAddContext] — utility
739
736
  - [CompositeAttachmentAdapter] — utility
737
+ - [CONTEXT_MIME] — utility
740
738
  - [ContextAttachmentAdapter] — utility
741
739
  - [createDirectiveText] — utility
740
+ - [EMPTY_COMPONENTS] — utility
742
741
  - [fileVariants] — utility
743
742
  - [formatFileSize] — utility
744
743
  - [getBase64Size] — utility
745
744
  - [getMimeTypeIcon] — utility
745
+ - [HARNESS_MIME] — utility
746
746
  - [HarnessAttachmentAdapter] — utility
747
747
  - [imageVariants] — utility
748
748
  - [isNewChatView] — utility
package/manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actioneer/ads",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "importPath": "@actioneer/ads",
5
5
  "styleImport": "@import \"@actioneer/ads/styles.css\";",
6
6
  "families": [
@@ -17,10 +17,10 @@
17
17
  ],
18
18
  "counts": {
19
19
  "total": 583,
20
- "component": 307,
20
+ "component": 298,
21
21
  "type": 236,
22
22
  "hook": 6,
23
- "util": 34
23
+ "util": 43
24
24
  },
25
25
  "tokens": [
26
26
  {
@@ -1618,48 +1618,6 @@
1618
1618
  "title"
1619
1619
  ]
1620
1620
  },
1621
- {
1622
- "name": "ANSWER_TOOL_DESCRIPTION",
1623
- "family": "Data display",
1624
- "kind": "component",
1625
- "importPath": "@actioneer/ads",
1626
- "module": "answer",
1627
- "showcaseUrl": "https://ads.actioneer.dev/#/ai/answer",
1628
- "variants": {
1629
- "tone": {
1630
- "values": [
1631
- "default",
1632
- "primary",
1633
- "success",
1634
- "warning",
1635
- "danger",
1636
- "info"
1637
- ],
1638
- "default": "default"
1639
- }
1640
- }
1641
- },
1642
- {
1643
- "name": "ANSWER_TOOL_NAME",
1644
- "family": "Data display",
1645
- "kind": "component",
1646
- "importPath": "@actioneer/ads",
1647
- "module": "answer",
1648
- "showcaseUrl": "https://ads.actioneer.dev/#/ai/answer",
1649
- "variants": {
1650
- "tone": {
1651
- "values": [
1652
- "default",
1653
- "primary",
1654
- "success",
1655
- "warning",
1656
- "danger",
1657
- "info"
1658
- ],
1659
- "default": "default"
1660
- }
1661
- }
1662
- },
1663
1621
  {
1664
1622
  "name": "AnswerRenderer",
1665
1623
  "family": "Data display",
@@ -3005,6 +2963,20 @@
3005
2963
  "importPath": "@actioneer/ads",
3006
2964
  "module": "answer"
3007
2965
  },
2966
+ {
2967
+ "name": "ANSWER_TOOL_DESCRIPTION",
2968
+ "family": "Data display",
2969
+ "kind": "util",
2970
+ "importPath": "@actioneer/ads",
2971
+ "module": "answer"
2972
+ },
2973
+ {
2974
+ "name": "ANSWER_TOOL_NAME",
2975
+ "family": "Data display",
2976
+ "kind": "util",
2977
+ "importPath": "@actioneer/ads",
2978
+ "module": "answer"
2979
+ },
3008
2980
  {
3009
2981
  "name": "AnswerFollowUpSchema",
3010
2982
  "family": "Data display",
@@ -4360,30 +4332,6 @@
4360
4332
  "onReady"
4361
4333
  ]
4362
4334
  },
4363
- {
4364
- "name": "VOICE_PALETTES",
4365
- "family": "AI Elements",
4366
- "kind": "component",
4367
- "importPath": "@actioneer/ads",
4368
- "module": "voice",
4369
- "showcaseUrl": "https://ads.actioneer.dev/#/ai/voice"
4370
- },
4371
- {
4372
- "name": "VOICE_STATES",
4373
- "family": "AI Elements",
4374
- "kind": "component",
4375
- "importPath": "@actioneer/ads",
4376
- "module": "voice",
4377
- "showcaseUrl": "https://ads.actioneer.dev/#/ai/voice"
4378
- },
4379
- {
4380
- "name": "VOICE_VARIANTS",
4381
- "family": "AI Elements",
4382
- "kind": "component",
4383
- "importPath": "@actioneer/ads",
4384
- "module": "voice",
4385
- "showcaseUrl": "https://ads.actioneer.dev/#/ai/voice"
4386
- },
4387
4335
  {
4388
4336
  "name": "VoiceConnectButton",
4389
4337
  "family": "AI Elements",
@@ -5071,14 +5019,25 @@
5071
5019
  "module": "tool"
5072
5020
  },
5073
5021
  {
5074
- "name": "ACTIONEER_FILE_ACCEPT",
5075
- "family": "Chat",
5076
- "kind": "component",
5022
+ "name": "VOICE_PALETTES",
5023
+ "family": "AI Elements",
5024
+ "kind": "util",
5077
5025
  "importPath": "@actioneer/ads",
5078
- "module": "attachment",
5079
- "vendored": true,
5080
- "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export.",
5081
- "showcaseUrl": "https://ads.actioneer.dev/#/demo/ask"
5026
+ "module": "voice"
5027
+ },
5028
+ {
5029
+ "name": "VOICE_STATES",
5030
+ "family": "AI Elements",
5031
+ "kind": "util",
5032
+ "importPath": "@actioneer/ads",
5033
+ "module": "voice"
5034
+ },
5035
+ {
5036
+ "name": "VOICE_VARIANTS",
5037
+ "family": "AI Elements",
5038
+ "kind": "util",
5039
+ "importPath": "@actioneer/ads",
5040
+ "module": "voice"
5082
5041
  },
5083
5042
  {
5084
5043
  "name": "AssistantActionBar",
@@ -5290,16 +5249,6 @@
5290
5249
  "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export.",
5291
5250
  "showcaseUrl": "https://ads.actioneer.dev/#/demo/ask"
5292
5251
  },
5293
- {
5294
- "name": "CONTEXT_MIME",
5295
- "family": "Chat",
5296
- "kind": "component",
5297
- "importPath": "@actioneer/ads",
5298
- "module": "composer-add-context",
5299
- "vendored": true,
5300
- "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export.",
5301
- "showcaseUrl": "https://ads.actioneer.dev/#/demo/ask"
5302
- },
5303
5252
  {
5304
5253
  "name": "DeepResearchProvider",
5305
5254
  "family": "Chat",
@@ -5330,16 +5279,6 @@
5330
5279
  "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export.",
5331
5280
  "showcaseUrl": "https://ads.actioneer.dev/#/demo/ask"
5332
5281
  },
5333
- {
5334
- "name": "EMPTY_COMPONENTS",
5335
- "family": "Chat",
5336
- "kind": "component",
5337
- "importPath": "@actioneer/ads",
5338
- "module": "thread-context",
5339
- "vendored": true,
5340
- "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export.",
5341
- "showcaseUrl": "https://ads.actioneer.dev/#/demo/ask"
5342
- },
5343
5282
  {
5344
5283
  "name": "ErrorRoot",
5345
5284
  "family": "Chat",
@@ -5430,16 +5369,6 @@
5430
5369
  "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export.",
5431
5370
  "showcaseUrl": "https://ads.actioneer.dev/#/demo/ask"
5432
5371
  },
5433
- {
5434
- "name": "HARNESS_MIME",
5435
- "family": "Chat",
5436
- "kind": "component",
5437
- "importPath": "@actioneer/ads",
5438
- "module": "composer-harness",
5439
- "vendored": true,
5440
- "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export.",
5441
- "showcaseUrl": "https://ads.actioneer.dev/#/demo/ask"
5442
- },
5443
5372
  {
5444
5373
  "name": "Image",
5445
5374
  "family": "Chat",
@@ -6138,6 +6067,15 @@
6138
6067
  "vendored": true,
6139
6068
  "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export."
6140
6069
  },
6070
+ {
6071
+ "name": "ACTIONEER_FILE_ACCEPT",
6072
+ "family": "Chat",
6073
+ "kind": "util",
6074
+ "importPath": "@actioneer/ads",
6075
+ "module": "attachment",
6076
+ "vendored": true,
6077
+ "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export."
6078
+ },
6141
6079
  {
6142
6080
  "name": "ActioneerFileAttachmentAdapter",
6143
6081
  "family": "Chat",
@@ -6165,6 +6103,15 @@
6165
6103
  "vendored": true,
6166
6104
  "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export."
6167
6105
  },
6106
+ {
6107
+ "name": "CONTEXT_MIME",
6108
+ "family": "Chat",
6109
+ "kind": "util",
6110
+ "importPath": "@actioneer/ads",
6111
+ "module": "composer-add-context",
6112
+ "vendored": true,
6113
+ "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export."
6114
+ },
6168
6115
  {
6169
6116
  "name": "ContextAttachmentAdapter",
6170
6117
  "family": "Chat",
@@ -6183,6 +6130,15 @@
6183
6130
  "vendored": true,
6184
6131
  "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export."
6185
6132
  },
6133
+ {
6134
+ "name": "EMPTY_COMPONENTS",
6135
+ "family": "Chat",
6136
+ "kind": "util",
6137
+ "importPath": "@actioneer/ads",
6138
+ "module": "thread-context",
6139
+ "vendored": true,
6140
+ "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export."
6141
+ },
6186
6142
  {
6187
6143
  "name": "fileVariants",
6188
6144
  "family": "Chat",
@@ -6219,6 +6175,15 @@
6219
6175
  "vendored": true,
6220
6176
  "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export."
6221
6177
  },
6178
+ {
6179
+ "name": "HARNESS_MIME",
6180
+ "family": "Chat",
6181
+ "kind": "util",
6182
+ "importPath": "@actioneer/ads",
6183
+ "module": "composer-harness",
6184
+ "vendored": true,
6185
+ "note": "Vendored assistant-ui component. Props follow upstream assistant-ui, not ADS conventions; the chat family needs an <AssistantRuntimeProvider> (chat runtime) and a <TooltipProvider> ancestor. Import from \"@actioneer/ads\" like any ADS export."
6186
+ },
6222
6187
  {
6223
6188
  "name": "HarnessAttachmentAdapter",
6224
6189
  "family": "Chat",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actioneer/ads",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Actioneer Design System 1.0 — React 19 + Tailwind v4 component library.",
5
5
  "type": "module",
6
6
  "sideEffects": [
package/styles.css CHANGED
@@ -39,20 +39,20 @@
39
39
  --font-sans: "Aribau Grotesk", ui-sans-serif, system-ui, -apple-system,
40
40
  "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
41
41
 
42
- /* ---- Type scale ---- base = 13px (0.8125rem). Root stays 16px so the
43
- spacing grid is unaffected; only text sizes are anchored to 13px. */
42
+ /* ---- Type scale ---- base = 14px (0.875rem). Root stays 16px so the
43
+ spacing grid is unaffected; only text sizes are anchored to 14px. */
44
44
  /* SIX sizes only — a deliberately small ladder (captions → display).
45
45
  Don't reintroduce 2xs/3xl/4xl or in-between steps; if a size feels
46
46
  missing, the answer is weight/color, not a new size. */
47
- --text-xs: 0.6875rem; /* 11px — captions, secondary text, table cells, keycaps */
47
+ --text-xs: 0.75rem; /* 12px — captions, secondary text, table cells, keycaps */
48
48
  --text-xs--line-height: 1rem;
49
- /* text-sm is aliased to text-xs (both 11px). The scale is intentionally
50
- 11 · 13 · 15 · 21 · 26 with no 12px tier — but keeping the token pointed
51
- at 11px stops any stray `text-sm` from falling back to Tailwind's
52
- default 14px, which would land off the scale entirely. */
53
- --text-sm: 0.6875rem;
49
+ /* text-sm is aliased to text-xs (both 12px). The scale is intentionally
50
+ 12 · 14 · 15 · 21 · 26 with no in-between tier — keeping the token
51
+ pointed at 12px stops any stray `text-sm` from falling back to
52
+ Tailwind's default 14px, which would silently read as base. */
53
+ --text-sm: 0.75rem;
54
54
  --text-sm--line-height: 1rem;
55
- --text-base: 0.8125rem; /* 13px — BASE body */
55
+ --text-base: 0.875rem; /* 14px — BASE body */
56
56
  --text-base--line-height: 1.25rem;
57
57
  --text-lg: 0.9375rem; /* 15px — emphasized body, section headings */
58
58
  --text-lg--line-height: 1.375rem;
@@ -470,7 +470,7 @@
470
470
  background-color: var(--background);
471
471
  color: var(--foreground);
472
472
  font-family: var(--font-sans);
473
- font-size: var(--text-base); /* 13px base */
473
+ font-size: var(--text-base); /* 14px base */
474
474
  font-feature-settings: "cv01", "ss01";
475
475
  font-synthesis-weight: none;
476
476
  }
package/theme.css CHANGED
@@ -12,20 +12,20 @@
12
12
  --font-sans: "Aribau Grotesk", ui-sans-serif, system-ui, -apple-system,
13
13
  "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
14
14
 
15
- /* ---- Type scale ---- base = 13px (0.8125rem). Root stays 16px so the
16
- spacing grid is unaffected; only text sizes are anchored to 13px. */
15
+ /* ---- Type scale ---- base = 14px (0.875rem). Root stays 16px so the
16
+ spacing grid is unaffected; only text sizes are anchored to 14px. */
17
17
  /* SIX sizes only — a deliberately small ladder (captions → display).
18
18
  Don't reintroduce 2xs/3xl/4xl or in-between steps; if a size feels
19
19
  missing, the answer is weight/color, not a new size. */
20
- --text-xs: 0.6875rem; /* 11px — captions, secondary text, table cells, keycaps */
20
+ --text-xs: 0.75rem; /* 12px — captions, secondary text, table cells, keycaps */
21
21
  --text-xs--line-height: 1rem;
22
- /* text-sm is aliased to text-xs (both 11px). The scale is intentionally
23
- 11 · 13 · 15 · 21 · 26 with no 12px tier — but keeping the token pointed
24
- at 11px stops any stray `text-sm` from falling back to Tailwind's
25
- default 14px, which would land off the scale entirely. */
26
- --text-sm: 0.6875rem;
22
+ /* text-sm is aliased to text-xs (both 12px). The scale is intentionally
23
+ 12 · 14 · 15 · 21 · 26 with no in-between tier — keeping the token
24
+ pointed at 12px stops any stray `text-sm` from falling back to
25
+ Tailwind's default 14px, which would silently read as base. */
26
+ --text-sm: 0.75rem;
27
27
  --text-sm--line-height: 1rem;
28
- --text-base: 0.8125rem; /* 13px — BASE body */
28
+ --text-base: 0.875rem; /* 14px — BASE body */
29
29
  --text-base--line-height: 1.25rem;
30
30
  --text-lg: 0.9375rem; /* 15px — emphasized body, section headings */
31
31
  --text-lg--line-height: 1.375rem;