@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 +11 -0
- package/README.md +3 -2
- package/dist/tools/integration.js +126 -4
- package/package.json +1 -1
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.
|
|
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
|
-
| **
|
|
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
|
|
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