@amityco/social-plus-vise 0.14.13 → 0.14.15

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/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@ All notable changes to `@amityco/social-plus-vise` are documented in this file.
4
4
 
5
5
  The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 0.14.15 — 2026-06-05
8
+
9
+ ### Fixed
10
+ - **Android Gradle catalog dependency detection:** `android.dependency.sdk` now recognizes `implementation(libs.amity.sdk)` when `gradle/libs.versions.toml` resolves the alias to `co.amity.android:amity-sdk`.
11
+
12
+ ### Verified
13
+ - Added a native-idiom regression fixture for Gradle version catalogs and confirmed the patched validator removes the false dependency warning in `music-player-android`.
14
+
15
+ ## 0.14.14 — 2026-06-05
16
+
17
+ ### Fixed
18
+ - **Android poll optional capability:** `post-poll-creation` now recognizes native Android poll post linking via `createPost().poll(pollId)` and `createPollPost(...)`, not only the TypeScript `createPost({ data: { pollId } })` shape.
19
+ - **Native optional sensor wording:** poll composer guidance now names the native post-builder path so agents do not need marker comments to satisfy the selected capability.
20
+
21
+ ### Verified
22
+ - Focused capability/product-flow tests and a marker-free `music-player-android` smoke passed with selected `post-poll-creation`.
23
+
7
24
  ## 0.14.13 — 2026-06-05
8
25
 
9
26
  ### Changed
@@ -403,14 +403,14 @@ export const OPTIONAL_CAPABILITIES = [
403
403
  { label: "SDK post creation/linking", symbols: [/\bcreatePollPost\b/i, /\bcreatePost\b/i] },
404
404
  ],
405
405
  sensors: [
406
- { label: "PollRepository.createPoll", regex: /PollRepository\.createPoll\s*\(|(?<![.\w])createPoll\s*\(/ },
406
+ { label: "PollRepository.createPoll", regex: /PollRepository\.createPoll\s*\(|(?<![\w])createPoll\s*\(/ },
407
407
  {
408
408
  label: "createPost links pollId",
409
- regex: /createPost\s*\(\s*\{[\s\S]*?data\s*:\s*\{[\s\S]*?\bpollId\b\s*(?::|[,}])/,
409
+ regex: /createPost\s*\(\s*\{[\s\S]*?data\s*:\s*\{[\s\S]*?\bpollId\b\s*(?::|[,}])|\bcreatePollPost\s*\(|\.createPost\s*\(\s*\)[\s\S]{0,1200}?\.poll\s*\(\s*pollId\b/,
410
410
  },
411
- { label: "PollRepository.votePoll", regex: /PollRepository\.votePoll\s*\(|(?<![.\w])votePoll\s*\(/ },
411
+ { label: "PollRepository.votePoll", regex: /PollRepository\.votePoll\s*\(|(?<![\w])votePoll\s*\(/ },
412
412
  ],
413
- hint: "If the user opts into polls, implement the createPoll -> createPost({ data: { pollId } }) chain and the votePoll read-side interaction.",
413
+ hint: "If the user opts into polls, implement the platform poll creation -> poll post linking chain, for example createPoll -> createPost({ data: { pollId } }) on TypeScript or createPost().poll(pollId) / createPollPost on native SDKs, plus the votePoll read-side interaction.",
414
414
  },
415
415
  {
416
416
  id: "post-edit",
package/dist/outcomes.js CHANGED
@@ -629,7 +629,7 @@ const addFeed = {
629
629
  evidence: ["social-plus-sdk/social/content-management/posts/creation/poll-post"],
630
630
  },
631
631
  {
632
- step: "If the post composer supports poll creation, implement the two-step creation chain: (1) `PollRepository.createPoll({ question, answers: [{ data: text }], answerType: 'single'|'multiple', closedIn? })` — returns a Poll with a pollId; (2) `PostRepository.createPost({ targetType, targetId, data: { text: '', pollId } })` links the poll to the feed post. Rendering poll answers (votePoll/unvotePoll) is the read-side; without both creation steps the poll composer silently does nothing. Offer a dedicated poll-builder UI (question input + dynamic answer list) so users can author polls inline.",
632
+ step: "If the post composer supports poll creation, implement the two-step creation chain: (1) create the poll with the platform SDK poll repository — returns a Poll/pollId; (2) link that poll into a post with the platform post builder, for example `PostRepository.createPost({ targetType, targetId, data: { text: '', pollId } })` on TypeScript/React Native or `createPost().poll(pollId)` / `createPollPost(...)` on native SDKs. Rendering poll answers (votePoll/unvotePoll) is the read-side; without both creation steps the poll composer silently does nothing. Offer a dedicated poll-builder UI (question input + dynamic answer list) so users can author polls inline.",
633
633
  evidence: [
634
634
  "social-plus-sdk/social/content-management/posts/creation/poll-post",
635
635
  "social-plus-sdk/social/posts",
@@ -189,7 +189,9 @@ async function validateAndroid(root) {
189
189
  ...(await existingFiles(root, ["app/build.gradle", "app/build.gradle.kts", "build.gradle", "build.gradle.kts", "settings.gradle", "settings.gradle.kts"])),
190
190
  ...gradleScripts,
191
191
  ])];
192
+ const versionCatalogFiles = (await findFiles(root, [".toml"], 50)).filter((f) => /(?:^|[\\/])gradle[\\/].*\.versions\.toml$/.test(f));
192
193
  const buildContent = await readMany(buildFiles);
194
+ const versionCatalogContent = await readMany(versionCatalogFiles);
193
195
  const sourceFiles = await findFiles(root, [".kt", ".java"], 300);
194
196
  const sourceContent = await readMany(sourceFiles);
195
197
  const setupFiles = filesMatching(sourceContent, [/AmityCoreClient\s*\.\s*setup/, /AmityClient\s*\.\s*setup/]);
@@ -208,7 +210,7 @@ async function validateAndroid(root) {
208
210
  findings.push(finding("android.application.class", "warning", "No custom Application class is declared in AndroidManifest.xml.", manifestPath, "Initialize social.plus once from an Application class instead of an Activity or composable lifecycle."));
209
211
  }
210
212
  }
211
- if (!containsAny(buildContent, [/co\.amity\.android:amity-sdk/, /Amity-Social-Cloud-Android-SDK/, /com\.github\.AmityCo/])) {
213
+ if (!hasAndroidSdkDependency(buildContent, versionCatalogContent)) {
212
214
  findings.push(finding("android.dependency.sdk", "warning", "No obvious social.plus Android SDK dependency was found in Gradle files.", relativeFile(root, buildFiles[0]), "Add the SDK dependency from the Android quick-start docs and keep all Amity dependencies on compatible versions."));
213
215
  }
214
216
  else if (containsAny(buildContent, [/co\.amity\.android:amity-sdk:\+/, /co\.amity\.android:amity-sdk:latest/i, /version\s*=\s*["']\+["']/])) {
@@ -2159,6 +2161,38 @@ function filesMatching(contents, patterns) {
2159
2161
  }
2160
2162
  return matches;
2161
2163
  }
2164
+ function hasAndroidSdkDependency(buildContent, versionCatalogContent) {
2165
+ if (containsAny(buildContent, [/co\.amity\.android:amity-sdk/, /Amity-Social-Cloud-Android-SDK/, /com\.github\.AmityCo/])) {
2166
+ return true;
2167
+ }
2168
+ const aliases = androidSdkCatalogAliases(versionCatalogContent);
2169
+ if (aliases.length === 0) {
2170
+ return false;
2171
+ }
2172
+ const accessorPatterns = aliases.flatMap((alias) => versionCatalogAccessors(alias).map((accessor) => new RegExp(`\\b(?:api|implementation|compileOnly|runtimeOnly|testImplementation|androidTestImplementation)\\s*\\(\\s*(?:platform\\s*\\(\\s*)?libs\\.${escapeRegExp(accessor)}\\b`)));
2173
+ return containsAny(buildContent, accessorPatterns);
2174
+ }
2175
+ function androidSdkCatalogAliases(contents) {
2176
+ const aliases = new Set();
2177
+ const entryPattern = /^\s*([A-Za-z0-9_.-]+)\s*=\s*(.+)$/gm;
2178
+ for (const content of contents.values()) {
2179
+ for (const match of content.matchAll(entryPattern)) {
2180
+ const alias = match[1];
2181
+ const value = match[2];
2182
+ if (/co\.amity\.android:amity-sdk/.test(value) ||
2183
+ (/group\s*=\s*["']co\.amity\.android["']/.test(value) && /name\s*=\s*["']amity-sdk["']/.test(value))) {
2184
+ aliases.add(alias);
2185
+ }
2186
+ }
2187
+ }
2188
+ return [...aliases];
2189
+ }
2190
+ function versionCatalogAccessors(alias) {
2191
+ return [...new Set([
2192
+ alias,
2193
+ alias.replace(/[-_]/g, "."),
2194
+ ])];
2195
+ }
2162
2196
  function containsAny(contents, patterns) {
2163
2197
  for (const content of contents.values()) {
2164
2198
  if (patterns.some((pattern) => pattern.test(content))) {
@@ -2167,6 +2201,9 @@ function containsAny(contents, patterns) {
2167
2201
  }
2168
2202
  return false;
2169
2203
  }
2204
+ function escapeRegExp(value) {
2205
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2206
+ }
2170
2207
  function containsAnyForFiles(contents, files, patterns) {
2171
2208
  return files.some((file) => {
2172
2209
  const content = contents.get(file) ?? "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/social-plus-vise",
3
- "version": "0.14.13",
3
+ "version": "0.14.15",
4
4
  "description": "Skill-guided deterministic CLI for social.plus SDK integration assistance.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",