@amityco/social-plus-vise 0.14.21 → 0.14.22

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,17 @@ 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.22 — 2026-06-05
8
+
9
+ ### Added
10
+ - **Multi-surface social workplans:** broad social requests now include a `socialWorkplan` sequence that decomposes feed, comments, chat, and profile work into ordered per-surface plans with focused `vise plan` / `vise init` commands.
11
+
12
+ ### Changed
13
+ - **Broad social intake:** when a multi-surface workplan exists, Vise no longer blocks the top-level plan on `feature_surface`; focused per-surface runs still use `--answer feature_surface=<surface>` before implementation.
14
+
15
+ ### Verified
16
+ - Product-flow, CLI, fixture, improvement-discovery, and host-agent smoke coverage now lock the multi-surface workplan path while preserving answered single-surface init behavior.
17
+
7
18
  ## 0.14.21 — 2026-06-05
8
19
 
9
20
  ### Changed
package/README.md CHANGED
@@ -161,12 +161,13 @@ Aggregate: **98/99 expected feed capabilities** and **27/27 selected optional ca
161
161
 
162
162
  ### Current Release Validation
163
163
 
164
- Version 0.14.21 carries current release proof around the full feed-forward, product-expectation, and validation flow:
164
+ Version 0.14.22 carries current release proof around the full feed-forward, product-expectation, and validation flow:
165
165
 
166
166
  | Surface | What was validated |
167
167
  |---|---|
168
168
  | **Product flow** | Local end-to-end smoke covers design extraction, plan feed-forward, blocking intake, answered init, capability check, design conformance, and sensor discovery. |
169
- | **Plan questions** | Plans surface blocking questions such as `feature_surface` and `design_contract_confirmation`, product-scope questions such as `feed_post_type_scope`, `feed_composer_type_scope`, `comment_tray_scope`, `chat_inbox_scope`, and `profile_identity_scope`, plus optional choices such as `feed_optional_capabilities`. |
169
+ | **Multi-surface planning** | Broad social requests are decomposed into a `socialWorkplan` sequence for feed, comments, chat, and profile work instead of forcing a single top-level surface choice. Each surface includes focused `vise plan` / `vise init` commands for the host agent to run when implementing that slice. |
170
+ | **Plan questions** | Plans surface blocking questions such as `design_contract_confirmation`, product-scope questions such as `feed_post_type_scope`, `feed_composer_type_scope`, `comment_tray_scope`, `chat_inbox_scope`, and `profile_identity_scope`, plus optional choices such as `feed_optional_capabilities`. Focused plans still accept `feature_surface` answers when the agent is ready to implement one surface. |
170
171
  | **Capability-to-sensor flow** | Vise checks platform support, matches the prompt to available capabilities, offers supported features as questions, records answers, and turns selected answers into sensors in `vise check`. |
171
172
  | **Shared product expectations** | Public IDs such as `feed.target-resolved`, `feed.post-type-scope-explicit`, `comments.creation-affordance`, `chat.channel-list-order-explicit`, `community.avatar-from-sdk`, `moderation.role-gated-action`, `follow.relationship-live`, `profile.identity-from-sdk`, `profile.social-counts`, and `notifications.tray-live` stay platform-agnostic while check results retain concrete `contractRuleId` and `validator.sensorId` evidence when deterministic sensors exist. |
172
173
  | **Rule detection** | TP-track dashboard detects **321/321 seeded rule gaps (100.0%)** in the static corpus. |
@@ -82,7 +82,21 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
82
82
  const designReview = designReviewGuidance(repoRoot, designContract, answers);
83
83
  const acceptedDesignContract = designReview.status === "accepted" ? designContract : null;
84
84
  const designBrief = acceptedDesignContract ? buildDesignBrief(acceptedDesignContract) : undefined;
85
- const intake = intakeFor(ctx, definition.intakeQuestions(ctx), outcome, designBrief, capabilityAvailability, designReview);
85
+ const socialWorkplan = await socialWorkplanFor({
86
+ request,
87
+ answers,
88
+ repoPath: repoRoot,
89
+ platform,
90
+ platforms: inspection.platforms,
91
+ designSignals: inspection.designSignals,
92
+ designBrief,
93
+ designReview,
94
+ sensors,
95
+ });
96
+ const outcomeQuestions = socialWorkplan
97
+ ? definition.intakeQuestions(ctx).filter((question) => question.id !== "feature_surface")
98
+ : definition.intakeQuestions(ctx);
99
+ const intake = intakeFor(ctx, outcomeQuestions, outcome, designBrief, capabilityAvailability, designReview);
86
100
  // Advisory SDK-version currency guidance (npm registry for TS/RN; version-agnostic
87
101
  // for native). Best-effort — degrades to greenfield "install latest + pin" if the
88
102
  // registry is unreachable. Never gates.
@@ -108,6 +122,7 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
108
122
  platform,
109
123
  supportLevel,
110
124
  intent: intentFor(request, definition.interpretation),
125
+ socialWorkplan,
111
126
  capabilityAvailability,
112
127
  designReview,
113
128
  decisionsRequired,
@@ -123,7 +138,7 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
123
138
  availableSurfaces: inspection.surfaces,
124
139
  applicableRules: await applicableCompliancePlanRuleSummaries(outcome, inspection.platforms),
125
140
  sensors: sensors.map((sensor) => ({ name: sensor.name, command: sensor.command, source: sensor.source })),
126
- stopConditions: composeStopConditions(ctx, definition.stopConditions(ctx), inspection.surfaces, surfacePath),
141
+ stopConditions: composeStopConditions(ctx, definition.stopConditions(ctx), inspection.surfaces, surfacePath, Boolean(socialWorkplan)),
127
142
  evidencePolicy: "Every implementation step must cite at least one detected file, docs page, validator rule, or required user input. If evidence is missing, stop and ask the user instead of inventing details.",
128
143
  designContract: acceptedDesignContract ? designContractGuidance(acceptedDesignContract) : undefined,
129
144
  completenessChecklist: completenessChecklistFor(outcome),
@@ -162,6 +177,113 @@ function optionalCapabilitiesFor(outcome, answers, request, availability) {
162
177
  selected: selectedOptionalCapabilityIds(outcome, answers, request, availableIds),
163
178
  };
164
179
  }
180
+ const SOCIAL_SURFACE_SEQUENCE = [
181
+ {
182
+ id: "feed",
183
+ outcome: "add-feed",
184
+ label: "Feed and post creation",
185
+ aliases: [/\b(feed|timeline|news feed|post list|posts?|create post|post creation|compose post|composer|reactions?)\b/i],
186
+ defaultForGenericBroad: true,
187
+ },
188
+ {
189
+ id: "comments",
190
+ outcome: "add-comments",
191
+ label: "Comments and replies",
192
+ aliases: [/\b(comments?|replies|reply|discussion thread|comment tray|comment composer)\b/i],
193
+ defaultForGenericBroad: true,
194
+ },
195
+ {
196
+ id: "chat",
197
+ outcome: "add-chat",
198
+ label: "Chat inbox and thread",
199
+ aliases: [/\b(chat|messaging|dm|direct message|conversation|group chat|channel|inbox)\b/i],
200
+ defaultForGenericBroad: true,
201
+ },
202
+ {
203
+ id: "profile",
204
+ outcome: "add-follow",
205
+ label: "Profile and follow graph",
206
+ aliases: [/\b(profile|profiles|follow|unfollow|followers?|following|social graph|relationship)\b/i],
207
+ defaultForGenericBroad: true,
208
+ },
209
+ {
210
+ id: "community",
211
+ outcome: "add-community",
212
+ label: "Community management",
213
+ aliases: [/\b(create|manage|join|leave|membership|members?|roles?|invitations?|categories?)\s+(?:a\s+|the\s+)?communit/i, /\bcommunity\s+(creation|management|members?|roles?|invitations?|categories|settings|moderation)\b/i],
214
+ },
215
+ {
216
+ id: "notifications",
217
+ outcome: "add-notifications",
218
+ label: "In-app notifications",
219
+ aliases: [/\b(notification tray|notification cent(?:er|re)|in-?app notifications?|notification settings?|notification preferences?)\b/i],
220
+ },
221
+ ];
222
+ async function socialWorkplanFor(args) {
223
+ if (!BROAD_SOCIAL_REGEX.test(args.request) || hasAnswer(args.answers, "feature_surface")) {
224
+ return undefined;
225
+ }
226
+ const matched = SOCIAL_SURFACE_SEQUENCE.filter((surface) => surface.aliases.some((pattern) => pattern.test(args.request)));
227
+ const selected = matched.length > 0
228
+ ? matched
229
+ : SOCIAL_SURFACE_SEQUENCE.filter((surface) => surface.defaultForGenericBroad);
230
+ if (selected.length <= 1) {
231
+ return undefined;
232
+ }
233
+ const sequence = [];
234
+ for (const surface of selected) {
235
+ const definition = getOutcomeDefinition(surface.outcome);
236
+ const capabilityAvailability = await platformCapabilityAvailability(surface.outcome, args.platform);
237
+ const surfaceAnswers = { ...args.answers, feature_surface: surface.id };
238
+ const surfaceCtx = {
239
+ ...planContextFor({
240
+ request: args.request,
241
+ outcome: surface.outcome,
242
+ platform: args.platform,
243
+ platforms: args.platforms,
244
+ designSignals: args.designSignals,
245
+ answers: surfaceAnswers,
246
+ }),
247
+ broadSocialRequest: false,
248
+ };
249
+ const intake = intakeFor(surfaceCtx, definition.intakeQuestions(surfaceCtx), surface.outcome, args.designBrief, capabilityAvailability, args.designReview);
250
+ const matchedPrompt = matched.some((match) => match.id === surface.id);
251
+ const commonArgs = `. --request ${shellQuote(args.request)} --answer feature_surface=${surface.id}`;
252
+ sequence.push({
253
+ id: surface.id,
254
+ order: sequence.length + 1,
255
+ outcome: surface.outcome,
256
+ label: surface.label,
257
+ matchedPrompt,
258
+ reason: matchedPrompt
259
+ ? `The request explicitly mentions ${surface.label.toLowerCase()}.`
260
+ : "The request is generic broad social work, so Vise includes this core surface in the default sequence.",
261
+ planCommand: `vise plan ${commonArgs}`,
262
+ initCommand: `vise init ${commonArgs}`,
263
+ intake: {
264
+ status: intake.status,
265
+ questions: intake.questions,
266
+ remainingBlocking: intake.remainingBlocking,
267
+ },
268
+ capabilityAvailability,
269
+ validation: ["validate_setup", "run_sensors", ...definition.validation(args.platform)],
270
+ docs: definition.docs(args.platform).filter((doc) => doc.path !== "unknown"),
271
+ optionalCapabilities: optionalCapabilitiesFor(surface.outcome, surfaceAnswers, args.request, capabilityAvailability),
272
+ sensors: args.sensors.map((sensor) => ({ name: sensor.name, command: sensor.command, source: sensor.source })),
273
+ });
274
+ }
275
+ const status = sequence.some((surface) => surface.intake.remainingBlocking > 0) ? "needs-answers" : "ready";
276
+ return {
277
+ kind: "social-multi-surface",
278
+ status,
279
+ note: "This broad social request is decomposed into ordered per-surface plans. Initialize and check one surface at a time so each sidecar has one outcome, while using this sequence as the coordinated product workplan.",
280
+ sequence,
281
+ nextStep: "Resolve each surface's blocking questions, then run the listed plan/init command for that surface before implementation. After each surface build, run `vise check .`, `vise sync .`, `vise validate .`, and `vise run-sensors .`.",
282
+ };
283
+ }
284
+ function shellQuote(value) {
285
+ return `'${value.replace(/'/g, "'\\''")}'`;
286
+ }
165
287
  function designReviewGuidance(repoRoot, contract, answers) {
166
288
  if (!contract) {
167
289
  return {
@@ -371,7 +493,7 @@ function composeImplementationRules(ctx, outcomeRules) {
371
493
  }
372
494
  return rules;
373
495
  }
374
- function composeStopConditions(ctx, outcomeStops, surfaces, surfacePath) {
496
+ function composeStopConditions(ctx, outcomeStops, surfaces, surfacePath, hasSocialWorkplan = false) {
375
497
  const stops = [
376
498
  "A required secret is missing and no safe ignored local env file or non-secret template path is clear.",
377
499
  "The target file is ambiguous or missing and no safe conventional location is detected.",
@@ -387,7 +509,7 @@ function composeStopConditions(ctx, outcomeStops, surfaces, surfacePath) {
387
509
  stops.push(`Multiple app surfaces detected (${surfaces.map((surface) => surface.path).join(", ")}); call this tool again with surfacePath set to the target app surface.`);
388
510
  }
389
511
  stops.push(...outcomeStops);
390
- if (ctx.broadSocialRequest && !hasAnswer(ctx.answers, "feature_surface")) {
512
+ if (ctx.broadSocialRequest && !hasAnswer(ctx.answers, "feature_surface") && !hasSocialWorkplan) {
391
513
  stops.push("The requested social feature is too broad; confirm the first feature surface before implementing.");
392
514
  }
393
515
  if (ctx.mentionsDesign && ctx.designSignals.length === 0 && !hasAnswer(ctx.answers, "design_source")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/social-plus-vise",
3
- "version": "0.14.21",
3
+ "version": "0.14.22",
4
4
  "description": "Skill-guided deterministic CLI for social.plus SDK integration assistance.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",