@amityco/social-plus-vise 1.8.0 → 1.8.1
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 +17 -0
- package/README.md +7 -5
- package/dist/server.js +6 -1
- package/dist/tools/integration.js +29 -6
- package/dist/tools/project.js +12 -4
- package/package.json +1 -1
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
|
+
## 1.8.1 — 2026-07-11
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Complete React Native journey proof.** The deterministic harness now runs the full governed feed journey on TypeScript, React Native, Android, Flutter, and iOS, including every documented exit state, scope-omit recovery, attestation and source-fingerprint lifecycle, contract drift, sensors, and runtime-evidence handoff.
|
|
11
|
+
- **Public-preview measurement contract.** A schema-validated, metadata-only report template defines the SDK custom-UI, UIKit quick-launch, and brownfield/day-2 evaluation tracks while forbidding source upload, recorded secrets, and customer identifiers. Structural, fresh-run, and external-adoption evidence remain explicitly separate.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **Locked UIKit plans stay on UIKit.** After `solution_path=uikit` is explicitly selected, the plan keeps an actionable UIKit installation/provider/customization step and omits contradictory direct-SDK outcome steps. Hybrid plans retain those steps only for differentiated behavior outside UIKit.
|
|
15
|
+
- **Explicit workplan surfaces are preserved.** An accepted Engagement Intelligence variant may add coherent companion surfaces, but it can no longer erase surfaces named directly by the user; bare plural `communities` is recognized in multi-surface requests.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Safe placeholders no longer mask later hardcoded values.** Literal scanning continues past documented placeholder IDs and API keys, including later matches in the same file or project, so a benign env fallback cannot hide a real committed secret or target.
|
|
19
|
+
- **Public contract wording.** The npm README now reflects the Node.js 20 minimum, fail-closed scan coverage, strict sensor selection, and the `vise check --ci` all-engagement release gate.
|
|
20
|
+
|
|
21
|
+
### Compatibility
|
|
22
|
+
- This patch changes no sidecar schema or exit code. SDK plans and unresolved UIKit decisions retain their existing branch visibility; only an explicitly locked UIKit route suppresses direct-SDK outcome steps.
|
|
23
|
+
|
|
7
24
|
## 1.8.0 — 2026-07-10
|
|
8
25
|
|
|
9
26
|
### Added
|
package/README.md
CHANGED
|
@@ -66,6 +66,8 @@ It ships as three layers:
|
|
|
66
66
|
|
|
67
67
|
> **New to social.plus?** Vise integrates the social.plus SDK. To adopt social.plus, [talk to our team](https://www.social.plus/contact/contact-sales?utm_source=vise&utm_medium=npm-readme&utm_campaign=ga). Existing customers get their **API key + region** from the [social.plus Console](https://console.socialplus.com) and can follow the [SDK getting-started guide](https://learn.social.plus/social-plus-sdk/getting-started/overview). You can install Vise and explore `vise inspect`/`vise plan` before you have credentials.
|
|
68
68
|
|
|
69
|
+
> **Runtime requirement:** Vise requires Node.js 20 or newer. Run `node --version` before installing if you are unsure which runtime your terminal or CI environment uses.
|
|
70
|
+
|
|
69
71
|
```sh
|
|
70
72
|
# 1. Install the CLI
|
|
71
73
|
npm install -g @amityco/social-plus-vise
|
|
@@ -202,7 +204,7 @@ Run `vise <command> --help` for full flags. JSON output is the default for agent
|
|
|
202
204
|
|---|---|
|
|
203
205
|
| `vise explore "<request>"` | Pre-credentials discovery: map a request to what social.plus offers (candidate outcome, capabilities, docs, next command). No project or API key needed |
|
|
204
206
|
| `vise doctor` | Verify install; print version, install path, docs source |
|
|
205
|
-
| `vise inspect [path]` | Detect platform, monorepo surfaces, design signals, available sensors |
|
|
207
|
+
| `vise inspect [path]` | Detect platform, monorepo surfaces, design signals, available sensors, and bounded scan coverage. An incomplete scan cannot initialize or produce a green check; select a concrete app surface in a large monorepo |
|
|
206
208
|
| `vise plan [path] --request "..." [--summary]` | Grounded implementation plan with intake questions and docs citations; `--summary` prints a compact route/intake view |
|
|
207
209
|
| `vise plan --summary "..."` | Shortcut for quick routing or discovery when the current directory is the repo |
|
|
208
210
|
| `vise plan-harness [path] --request "..."` | Pre-planning step: build the harness around the request |
|
|
@@ -253,7 +255,7 @@ Everything in this group is local and advisory: no uploads, no `vise check` exit
|
|
|
253
255
|
| Command | Purpose |
|
|
254
256
|
|---|---|
|
|
255
257
|
| `vise check [path]` | Re-validate against the recorded contract: `green`, `needs-attestation`, `deterministic-failures`, `blocked`, `contract-drift`, `completeness-gap`, `selected-capability-failures`, `no-platform` (no SDK platform detected — reported as a failure, not a vacuous green), or `runtime-proof-waived` |
|
|
256
|
-
| `vise check [path] --ci` | Read-only
|
|
258
|
+
| `vise check [path] --ci` | Read-only release gate for the active contract **and every recorded engagement**. Active non-green keeps its normal exit code; active green with completed-work drift exits `11` |
|
|
257
259
|
| `vise check [path] --allow-proof-waiver` | Accept an honest `runtime-proof-waived` result (from `vise smoke waive`) as passing (exit 0) instead of blocking; without it a waiver blocks CI by default |
|
|
258
260
|
| `vise check [path] --new-only` | **Brownfield gate.** With a recorded baseline, gate only on rule findings introduced *since* the baseline (pre-existing ones are reported but excluded). The outcome's completeness checklist and selected optional capabilities are **never** excluded — they are the engagement's deliverables and gate like a default check. Default `check` always gates on everything |
|
|
259
261
|
| `vise check [path] --engagement <outcome>` | **Re-verdict one recorded engagement** (from `sp-vise/engagements/`) against the current ruleset and code. Exit `11` on drift, `0` when it still holds; never the active engagement's codes. `ruleset_upgraded` discloses when the installed ruleset moved since it was recorded |
|
|
@@ -269,7 +271,7 @@ Everything in this group is local and advisory: no uploads, no `vise check` exit
|
|
|
269
271
|
|
|
270
272
|
| Command | Purpose |
|
|
271
273
|
|---|---|
|
|
272
|
-
| `vise run-sensors [path] [--dry-run]` | Run detected project scripts (npm, Gradle, Flutter, lint, typecheck, SDK smokes); `--dry-run` lists without executing |
|
|
274
|
+
| `vise run-sensors [path] [--dry-run] [--include "<sensor name>"]` | Run detected project scripts (npm, Gradle, Flutter, lint, typecheck, SDK smokes); `--dry-run` lists without executing. Every explicit include must match a detected sensor or the command fails; output is bounded and timed-out descendants are terminated |
|
|
273
275
|
| `vise smoke [path] --log <file>` | Assess a captured mount-smoke log into a pass/fail verdict + record evidence. `expect: "populated"` requires `loaded count=N` with `N > 0`; this catches session-establish and empty-data gaps that static checks cannot see |
|
|
274
276
|
| `vise smoke waive [path] --reason "..." [--mode declined\|deviceless]` | Record an auditable runtime-proof waiver when proof is declined or no device/emulator is available, instead of faking evidence. `vise check` then reports `runtime-proof-waived` (exit 9; accept with `--allow-proof-waiver`) rather than a red-forever live surface |
|
|
275
277
|
| `vise install-skill --target <host>` | Install the bundled skill into a coding host (see [Quick Start](#quick-start)) |
|
|
@@ -321,7 +323,7 @@ jobs:
|
|
|
321
323
|
- run: vise check . --ci
|
|
322
324
|
```
|
|
323
325
|
|
|
324
|
-
`vise check --ci` is read-only — it never updates `sp-vise/` — and its JSON output includes a structured `ci` block for pipeline logs.
|
|
326
|
+
`vise check --ci` is read-only — it never updates `sp-vise/` — and its JSON output includes a structured `ci` block for pipeline logs. It automatically re-verdicts every recorded engagement, so CI holds previously completed surfaces green without a second `--all-engagements` command.
|
|
325
327
|
|
|
326
328
|
| Exit code | Meaning |
|
|
327
329
|
|---|---|
|
|
@@ -334,7 +336,7 @@ jobs:
|
|
|
334
336
|
| `6` | An explicitly selected optional capability failed its source sensors |
|
|
335
337
|
| `8` | No SDK platform detected (`no-platform`) — reported as a failure, never a vacuous green |
|
|
336
338
|
| `9` | Runtime proof waived (`runtime-proof-waived`) — accept explicitly with `--allow-proof-waiver` |
|
|
337
|
-
| `11` | Engagement drift (`--engagement
|
|
339
|
+
| `11` | Engagement drift (`--ci`, `--engagement`, or `--all-engagements`): the active gate is green but a recorded engagement re-verdicts non-green — a previously finished surface no longer holds |
|
|
338
340
|
|
|
339
341
|
## Compliance Contract
|
|
340
342
|
|
package/dist/server.js
CHANGED
|
@@ -1595,7 +1595,12 @@ async function activeBlueprint(repoRoot, request, plan) {
|
|
|
1595
1595
|
const planSequence = socialWorkplanSequence(plan);
|
|
1596
1596
|
const flowFallback = await socialWorkplanSequenceFromFlow(repoRoot, request);
|
|
1597
1597
|
const canonicalRequest = flowFallback?.request ?? request;
|
|
1598
|
-
const
|
|
1598
|
+
const isCanonicalRequest = normalizeWorkflowRequest(request) === normalizeWorkflowRequest(canonicalRequest);
|
|
1599
|
+
const full = flowFallback && !isCanonicalRequest
|
|
1600
|
+
? flowFallback.sequence
|
|
1601
|
+
: planSequence.length
|
|
1602
|
+
? planSequence
|
|
1603
|
+
: flowFallback?.sequence ?? [];
|
|
1599
1604
|
const omitted = await readOmittedSurfaces(repoRoot, canonicalRequest);
|
|
1600
1605
|
const omittedIds = new Set(omitted.map((item) => item.id));
|
|
1601
1606
|
return { sequence: full.filter((surface) => !omittedIds.has(surface.id)), omitted, canonicalRequest };
|
|
@@ -218,7 +218,7 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
|
|
|
218
218
|
...solutionPathImplementationSteps(solutionPath),
|
|
219
219
|
...uikitCustomizationImplementationSteps(uikitCustomization),
|
|
220
220
|
...crossPlatformHandoffSteps,
|
|
221
|
-
...definition.implementationSteps(ctx),
|
|
221
|
+
...outcomeImplementationStepsForSolutionPath(solutionPath, definition.implementationSteps(ctx)),
|
|
222
222
|
],
|
|
223
223
|
validation: ["validate_setup", "run_sensors", ...definition.validation(platform)],
|
|
224
224
|
...(clarify ? { clarify } : {}),
|
|
@@ -442,18 +442,30 @@ function solutionPathDecisions(solutionPath, answers) {
|
|
|
442
442
|
];
|
|
443
443
|
}
|
|
444
444
|
function solutionPathImplementationSteps(solutionPath) {
|
|
445
|
-
|
|
445
|
+
const unresolved = solutionPath.decision.requiredBeforeHandRolledUi;
|
|
446
|
+
if (solutionPath.recommendation === "sdk" && !unresolved) {
|
|
446
447
|
return [];
|
|
447
448
|
}
|
|
449
|
+
const step = solutionPath.recommendation === "uikit"
|
|
450
|
+
? unresolved
|
|
451
|
+
? "Confirm the social.plus UIKit path before building standard social UI from SDK primitives; use UIKit install/auth/customization docs as the primary implementation source. The SDK feed/chat/profile steps that follow apply ONLY to the direct-SDK (or hybrid SDK-side) route — do not hand-roll the standard surface from them when the customer is using UIKit."
|
|
452
|
+
: "Implement the explicitly selected social.plus UIKit path as the primary artifact: follow UIKit installation, authentication, provider/page, behavior, and customization guidance. Direct-SDK outcome steps are intentionally omitted for this locked UIKit route; do not hand-roll the standard social surface from SDK primitives."
|
|
453
|
+
: solutionPath.recommendation === "hybrid" && !unresolved
|
|
454
|
+
? "Implement the explicitly selected hybrid path: use UIKit for standard social surfaces, and apply the direct-SDK outcome steps only to the differentiated app-specific behavior that UIKit does not cover. Do not rebuild UIKit-covered surfaces from SDK primitives."
|
|
455
|
+
: "Resolve whether this is a UIKit, SDK, or hybrid build before starting UI implementation; the SDK implementation steps that follow apply to the SDK/hybrid route, not to a UIKit build. Do not let mixed speed/customization signals collapse into a hand-rolled SDK UI by default.";
|
|
448
456
|
return [
|
|
449
457
|
{
|
|
450
|
-
step
|
|
451
|
-
? "Confirm the social.plus UIKit path before building standard social UI from SDK primitives; use UIKit install/auth/customization docs as the primary implementation source. The SDK feed/chat/profile steps that follow apply ONLY to the direct-SDK (or hybrid SDK-side) route — do not hand-roll the standard surface from them when the customer is using UIKit."
|
|
452
|
-
: "Resolve whether this is a UIKit, SDK, or hybrid build before starting UI implementation; the SDK implementation steps that follow apply to the SDK/hybrid route, not to a UIKit build. Do not let mixed speed/customization signals collapse into a hand-rolled SDK UI by default.",
|
|
458
|
+
step,
|
|
453
459
|
evidence: ["solutionPath", ...solutionPath.evidence],
|
|
454
460
|
},
|
|
455
461
|
];
|
|
456
462
|
}
|
|
463
|
+
function outcomeImplementationStepsForSolutionPath(solutionPath, outcomeSteps) {
|
|
464
|
+
if (solutionPath.recommendation === "uikit" && !solutionPath.decision.requiredBeforeHandRolledUi) {
|
|
465
|
+
return [];
|
|
466
|
+
}
|
|
467
|
+
return outcomeSteps;
|
|
468
|
+
}
|
|
457
469
|
function solutionPathImplementationRules(solutionPath) {
|
|
458
470
|
if (solutionPath.recommendation === "sdk" && !solutionPath.decision.requiredBeforeHandRolledUi) {
|
|
459
471
|
return [];
|
|
@@ -719,7 +731,11 @@ const SOCIAL_SURFACE_SEQUENCE = [
|
|
|
719
731
|
id: "community",
|
|
720
732
|
outcome: "add-community",
|
|
721
733
|
label: "Community management",
|
|
722
|
-
aliases: [
|
|
734
|
+
aliases: [
|
|
735
|
+
/\bcommunities\b/i,
|
|
736
|
+
/\b(create|manage|join|leave|membership|members?|roles?|invitations?|categories?)\s+(?:a\s+|the\s+)?communit/i,
|
|
737
|
+
/\bcommunity\s+(creation|management|members?|roles?|invitations?|categories|settings|moderation)\b/i,
|
|
738
|
+
],
|
|
723
739
|
},
|
|
724
740
|
{
|
|
725
741
|
id: "notifications",
|
|
@@ -743,6 +759,13 @@ async function socialWorkplanFor(args) {
|
|
|
743
759
|
const surface = SOCIAL_SURFACE_SEQUENCE.find((item) => item.id === hint.id);
|
|
744
760
|
return surface ? [{ surface, creativeHint: hint }] : [];
|
|
745
761
|
});
|
|
762
|
+
const selectedIds = new Set(selected.map((entry) => entry.surface.id));
|
|
763
|
+
for (const surface of matched) {
|
|
764
|
+
if (!selectedIds.has(surface.id)) {
|
|
765
|
+
selected.push({ surface });
|
|
766
|
+
selectedIds.add(surface.id);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
746
769
|
if (selected.length <= 1) {
|
|
747
770
|
return undefined;
|
|
748
771
|
}
|
package/dist/tools/project.js
CHANGED
|
@@ -2966,11 +2966,19 @@ function firstLiteralAssignment(contents, patterns, platform) {
|
|
|
2966
2966
|
for (const [file, rawContent] of contents) {
|
|
2967
2967
|
const content = commentStripped(file, platform, rawContent);
|
|
2968
2968
|
for (const pattern of patterns) {
|
|
2969
|
-
pattern.
|
|
2970
|
-
const
|
|
2971
|
-
|
|
2969
|
+
const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
|
|
2970
|
+
const matcher = new RegExp(pattern.source, flags);
|
|
2971
|
+
let match;
|
|
2972
|
+
while ((match = matcher.exec(content)) !== null) {
|
|
2973
|
+
if (!match[1]) {
|
|
2974
|
+
continue;
|
|
2975
|
+
}
|
|
2976
|
+
const value = match[1].trim();
|
|
2977
|
+
if (isAllowedPlaceholder(value)) {
|
|
2978
|
+
continue;
|
|
2979
|
+
}
|
|
2972
2980
|
const name = match[0].split(/[=:]/)[0]?.trim() ?? "literal";
|
|
2973
|
-
return { file, name, value
|
|
2981
|
+
return { file, name, value };
|
|
2974
2982
|
}
|
|
2975
2983
|
}
|
|
2976
2984
|
}
|