@amityco/social-plus-vise 1.2.0 → 1.4.0
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 +75 -2
- package/README.md +23 -10
- package/dist/capabilities.js +35 -4
- package/dist/entryState.js +71 -0
- package/dist/experience.js +70 -0
- package/dist/explore.js +51 -0
- package/dist/flow.js +382 -0
- package/dist/humanFormat.js +251 -0
- package/dist/intake.js +117 -0
- package/dist/intelligence/placement.js +2 -1
- package/dist/outcomes.js +141 -42
- package/dist/productExpectations.js +15 -0
- package/dist/requestReadiness.js +99 -0
- package/dist/server.js +675 -56
- package/dist/sidecar.js +5 -0
- package/dist/solutionPath.js +2 -2
- package/dist/tools/compliance.js +1014 -133
- package/dist/tools/creative.js +14 -12
- package/dist/tools/debug.js +83 -26
- package/dist/tools/design.js +344 -14
- package/dist/tools/experienceCompiler.js +1 -1
- package/dist/tools/experienceSensors.js +1 -1
- package/dist/tools/harness.js +13 -0
- package/dist/tools/integration.js +263 -90
- package/dist/tools/learning.js +1 -3
- package/dist/tools/project.js +987 -72
- package/dist/tools/sdkFacts.js +8 -1
- package/dist/tools/smoke.js +134 -0
- package/dist/tools/uxHarness.js +54 -6
- package/dist/uikitCustomization.js +22 -6
- package/dist/version.js +7 -3
- package/package.json +1 -1
- package/packages/intelligence/catalog/catalog.schema.json +1 -1
- package/packages/intelligence/catalog/experience-objects.json +2 -2
- package/packages/intelligence/catalog/variants.json +24 -0
- package/rules/event.yaml +3 -0
- package/rules/feed.yaml +251 -0
- package/rules/invitation.yaml +4 -0
- package/rules/live-data.yaml +110 -0
- package/rules/notification-tray.yaml +4 -0
- package/rules/poll.yaml +5 -0
- package/rules/sdk-lifecycle.yaml +559 -0
- package/rules/search.yaml +5 -0
- package/rules/security.yaml +12 -0
- package/rules/story.yaml +5 -0
- package/rules/user-blocking.yaml +5 -0
- package/skills/social-plus-vise/SKILL.md +163 -15
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,80 @@ 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
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
No changes yet.
|
|
10
|
+
|
|
11
|
+
## 1.4.0 — 2026-07-02
|
|
12
|
+
|
|
13
|
+
**Entry-state flow + alignment gate.** `vise plan`/`init` now run a persona-free entry-state flow ahead of the build. A broad, multi-surface goal expands into a **blueprint** — the surfaces and experience to build — and for that journey `vise init` requires a human **blueprint sign-off** before it scaffolds anything: the *alignment gate* ("are we building the right thing?"), distinct from and complementary to the deterministic compliance gate ("did we build it the right way?"). The sign-off is a SELECT, not a rubber stamp — when the solution path is undecided it hard-picks `sdk` / `uikit` / `hybrid` first and surfaces candidate experiences, persists the choice, re-arms if the path/journey/design source changes, and cannot be bypassed. (A single-surface init is gated by intake/clarify, not the blueprint sign-off.)
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **Clarify-to-classify.** When a request is too vague to classify or names a capability the SDK doesn't support, `vise plan` returns a structured `clarify` block instead of silently scaffolding, and `vise init` blocks (exit 7) rather than guessing.
|
|
17
|
+
- **Runtime-readiness consent + no-data gate.** The blueprint runtime-readiness packet now makes natural target discovery explicit, tells agents what to do when tenant data is absent (Console prep or safe SDK seed data before populated proof), and requires asking the user before expensive browser/simulator/emulator runtime proof. If proof or data setup is declined, agents must report the remaining runtime risks instead of claiming product proof.
|
|
18
|
+
- **All-platform dogfood evidence packet.** Recorded the 2026-06-28 TypeScript, React Native, Android, Flutter, and iOS improvement loop with matrix results, runtime screenshots, validation commands, cleanup notes, and the explicit native caveat that RN/Flutter currently have starter launch proof but not archived completed-output proof.
|
|
19
|
+
- **SDK field-shape correctness advisories (TS/JS).** Advisory detectors (`warning`, never gate `vise check`) that catch *wrong-shape* use of correctly-named SDK symbols — a reaction count read as an object off a `number`, a follow `status` compared to a value absent from the SDK enum — grounded in the extracted SDK type model. The wrong-field class an exact-name presence check can't see.
|
|
20
|
+
- **Loading-state UX advisory (TS/JS).** Advisory detector that flags an SDK live-data binding rendered with no loading state nearby (the empty/blank-flash class), independent of the empty/error completeness baseline. Recognizes loaders by stem-matching the rendered component (skeleton/shimmer/spinner/progress families, library-agnostic) rather than an exact-name allowlist.
|
|
21
|
+
- **First-class `livestream` surface** and curated **messaging / discussion / creator experience bundles** in the Engagement Intelligence catalog.
|
|
22
|
+
- **`vise workplan trim`** — deliberately omit a companion surface on a multi-surface blueprint; requires a `--reason` and re-arms the blueprint sign-off (the trimmed blueprint must be re-signed before proceeding).
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- **Experience-calibration dogfood harness honors current governance.** The harness now accepts EI variants with grounded rationale/confidence, performs the multi-surface blueprint sign-off with a digest before `init`, and preserves the runtime-boundary checks for score/ranking/upload/customer-data behavior.
|
|
26
|
+
- **ID-free target defaults.** Feed, follow, community, and chat intakes default to their ID-free / self / discovery sources rather than a hardcoded community or target id, so the agent never invents an id it wasn't given (advisory; gates unchanged).
|
|
27
|
+
- **React Native dogfood starter launchability.** The RN native starter now uses `expo run:ios` / `expo run:android` for runtime proof and pins `react-native-screens` to the Expo SDK 53-compatible range that builds on the local iOS simulator.
|
|
28
|
+
- **One design sign-off per journey.** On a multi-surface blueprint the per-surface design-preview confirmation is folded into the single blueprint sign-off — you approve the design once for the whole journey rather than per surface.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
**File-scoped attestation** — closes a false-negative in the merge gate found while verifying the brownfield baseline (pf-053 follow-up). Previously `vise attest` greened a rule **globally**: a session could attest a rule once over a legacy violation and then ship NEW code violating the *same* rule undetected — and `vise check --new-only` could **not** catch it, because the attested rule was green before baseline subtraction ran. An attestation is now **scoped to the violator files present at attest time**; a live violation in any file the attestation never covered re-gates the rule (`attestation-needed` / `deterministic-fail`, naming the uncovered file).
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- **`vise check` re-gates new co-located violators of an attested rule.** For rules on the file-scopable allowlist, the attested green now covers only the reviewed files. This is intentionally stricter than before — a previously-masked new violation now gates. Rules **not** on the allowlist (project-aggregate rules such as `client.region`, whose finding points at a representative file rather than a located violation) keep the historical rule-global behavior, so this never false-gates. The allowlist (`FILE_SCOPABLE_SENSOR_SUFFIXES` in `compliance.ts`) covers **all 44** verified loop-file-scoped attestable per-file rules — the complete set of located-misuse detectors (e.g. `posts.status-filter-applied`, `feed.post-datatype-handled`, `live-collection.api-mismatch`, `comments.target-resolved`, `chat.sort-explicit`, `comments.query-has-limit`, `livestream.deprecated-stream`, `session-handler.retained`, `logging.no-secret-in-log`, the per-surface `*.live-collection` rules). Each entry is guarded by a test that fails if it stops resolving to a real attestable rule.
|
|
36
|
+
- **~19 per-file sensors converted to enumerate every violator** (they previously stopped at the first via an outer-loop `break` / `return findings` / per-rule dedup), so a file-scoped attestation over one violator can't mask a co-located new violation of the same rule. Covers `feed.post-datatype-handled`, `comments.target-resolved`, `chat.channel-type-dm`, the deprecated-chat/livestream detectors, `community.avatar-from-sdk`, `feed.poll-answer-data-shape`, `comments.query-has-limit`, `chat.sort-explicit`, `profile.social-counts-from-sdk`, `community.display-name-from-sdk`, `feed.room-post-fetched`, `feed.ui-states-present`, `session-handler.retained`, `client.no-ssr-init`, `follow.status-subscription`, and the `logging.no-secret-in-log` / `logging.no-pii-in-log` line scanner. (Non-attestable deterministic-fail rules like `chat.channel-target-resolved` are unaffected — they can't be attested, so there is nothing to scope.)
|
|
37
|
+
|
|
38
|
+
### Changed (cont.)
|
|
39
|
+
- **Attest-while-clean bypass — closed.** A file-scopable rule is now **always** marked `file_scoped`, even when attested while its sensor is *not* firing. The covered set is then just the attester's evidence files (often empty), so a violation introduced **later** is uncovered and re-gates (`attestation-needed`), instead of being masked rule-globally by an unscoped attestation. Guarded by a mutation-verified CLI test: a clean attest with prose-only evidence (empty covered set) → a new violator re-gates under `--new-only`. Old (pre-marker) attestations remain grandfathered to rule-global, so `test:sidecar-compat` stays green.
|
|
40
|
+
|
|
41
|
+
### Known residuals (disclosed)
|
|
42
|
+
- **Non-`"."` surface paths** are believed correct (attest and check both resolve via `sourceRootForCompliance` / `resolveEvidenceSourcePath`, which coincide with `inspection.effectiveRoot` when the surface root is set) but are **not yet covered by a test** — all current tests use surface `"."`.
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
- **`attest` records `file_scoped: true` + `source_fingerprints` for the live-violator files** (tagged `live_sensor_violator`) when a file-scopable rule is attested; the CLI response echoes `file_scoped` and `scoped_files`. The check-time pf-068 contradiction disclosure is unchanged; this adds the *check-time* enforcement it could only warn about at attest time.
|
|
46
|
+
|
|
47
|
+
### Compatibility
|
|
48
|
+
- **Additive sidecar field.** Attestation files gain an optional `file_scoped` flag and `live_sensor_violator` `source_fingerprints`; old attestations lack the flag and keep rule-global behavior (the frozen 1.1.0 `test:sidecar-compat` baseline stays green). The rule corpus and contract digest are unchanged, so existing attestations are not invalidated. **Behavior note:** a file-scoped rule that was attested over a legacy violation will now re-gate if the *same* rule is violated in a new/uncovered file — re-attest (covering the new file) or fix it. A bare `vise check` and `--new-only` both honor the new scope.
|
|
49
|
+
- **Re-run `vise baseline` after upgrading.** The converted sensors now emit one finding per violating file; for a rule with multiple violators in the SAME file, the single displayed `finding.file` can shift (first→last violator), which changes that rule's `rule@file` baseline key. A `baseline.json` recorded before this change may therefore not match the new key for such a rule, causing a pre-existing finding to re-gate under `--new-only`. The ruleset digest is unchanged so the staleness guard does not flag it — re-run `vise baseline` once after upgrading to refresh the keys.
|
|
50
|
+
|
|
51
|
+
## 1.3.0 — 2026-06-19
|
|
52
|
+
|
|
53
|
+
Discovery + readability surface, CLI/report honesty, and a batch of detector-precision fixes from two real-agent persona-dogfood sweeps (Sonnet 4.6), each fix mutation-verified and the whole batch adversarially reviewed. **No change to `vise check` exit codes, compliance rules, or sidecar *formats*** — the sidecar gains only **additive** fields (see Compatibility). The rule corpus is unchanged, so the contract digest is stable and no re-attestation is triggered.
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
- **`vise explore "<request>"`** — a pre-credentials, read-only discovery command. It maps a free-text request to a candidate feature/setup outcome (and lists the full menu when it can't, instead of dead-ending on `outcome:unknown`); each route carries the capabilities involved, the canonical docs, and the `vise plan` command to start. No project or API key required.
|
|
57
|
+
- **`--format human`** on the read commands (`check` · `status` · `plan` · `doctor` · `explain` · `explore`). **JSON stays the default** — agents, CI, and sidecar-consuming flows parse stdout, so the default is unchanged; `--format human` is opt-in.
|
|
58
|
+
- **`vise explain`** with no id now **enumerates the valid rule ids** (grouped by public id → contract ids) instead of erroring.
|
|
59
|
+
- **`completeness` / selected-capability detail** is now surfaced by **`vise status`** and the init-time `findings.json` snapshot, mirroring `vise check`. Previously a `needs-attestation` / `deterministic-failures` headline (status precedence) hid a co-existing completeness-gap from anything reading those two surfaces.
|
|
60
|
+
- **Brownfield baseline gate.** `vise baseline` (and `vise init --baseline`) snapshots the current pre-existing findings to `sp-vise/baseline.json`, and **`vise check --new-only`** (also `status --new-only`) gates only on findings introduced *since* the baseline — legacy findings are reported (`baselined: true`) but excluded. This makes `check` usable as a per-PR merge gate on an existing codebase. **Gate integrity:** subtraction is an explicit per-invocation flag, *never* the default — a bare `vise check` always gates on everything, so a green exit can never silently mean "no *new* gaps." A stale baseline (ruleset digest moved since it was recorded) is **not** applied (fail-safe: gate on everything and disclose `baseline.stale`). The artifact is additive — absent ⇒ unchanged behavior; the frozen sidecar-compat baseline is unaffected. Known v1 limitation, surfaced in the check output as `baseline.residual_caveat`: the rule+file key can mask a new violation of an already-baselined rule in the same file.
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
- **Honesty of reports.** `attest` re-runs the deterministic sensor and **discloses** a live violation (without refusing — attestation is the override path); `check`/`status` carry an `evidence_basis_note` (plain-language "passed by absence" caveat); `vise status` propagates the body exit code to the process exit; `--ci` `blockingResultStatuses` enumerates every non-green status (incl. completeness-gap, selected-capability-failures); `explain` surfaces the feedforward/symptoms/inferential corpus fields; `doctor` surfaces the support channel.
|
|
64
|
+
- **`vise debug`** correlates runtime-only symptom matches regardless of compliance status (a passing rule is framed as a runtime/out-of-sensor-reach signal, never a compliance failure), and maps `Cannot find module` / `MODULE_NOT_FOUND` for a **bare package** to a concrete `npm install` remediation — a failing correlated rule still wins the headline (the module hint rides as a secondary note).
|
|
65
|
+
- **`vise init` intake validation.** Out-of-enum values (on closed-enum questions) and unrecognized `--answer` keys now produce advisory **warnings** instead of being silently accepted/dropped. Warnings only — never a rejection — so multi-select and free-form answers are unaffected.
|
|
66
|
+
- **`engagement --scope`** accepts the full planner outcome vocabulary (derived from the classifier order), including `add-follow` / `add-community` / `add-notifications`, which were previously rejected.
|
|
67
|
+
- **Classifier routing.** "community profile" → `add-community`, "user/member profile" (with a social qualifier) → `add-follow`, "notifications tray" → `add-notifications`; a non-social "company/performance/memory profile" stays `unknown`.
|
|
68
|
+
- **`design check` coverage** splits `referenced_in_app` vs `seeded_only_tokens` — tokens that appear only in the Vise-scaffolded token file no longer inflate a false 100% (the raw `referenced` count is unchanged for back-compat).
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
- **Advisory routing precision** (advisory-only; no gate change): an explicit "build it with our own component" / "replace the UIKit surface" ask now routes SDK/custom-UI instead of Dynamic-UI; Console/theming phrasing corrected.
|
|
72
|
+
- **Detector false positives.** `posts.status-filtered` no longer mis-attributes to `.d.ts` type stubs; `chat.send-error-handling` requires a real message *send* call (a read-only `markRead` view no longer fires); Android `comments.observer-cleanup` recognizes structured-concurrency cleanup (`stateIn(viewModelScope)` / `collectAsStateWithLifecycle` / `repeatOnLifecycle` / `DisposableEffect`), anchored to the observer's own chain; a negated "no custom code" no longer trips behavior-overrides; `scope-omit` reasons must be auditable (≥ 8 chars).
|
|
73
|
+
- **`*.sdk.version.pinned` messages** now name each platform's real uncontrolled tokens (Android `+`/`:latest`, Flutter `any`, iOS moving branch / unspecified CocoaPods, TypeScript `latest`/`*`/`x` with `^`/`~` accepted). The rule **rationale is unchanged** (it is part of the contract digest; rewording it would force re-attestation — see the digest note in maintainer docs).
|
|
74
|
+
- **`sdk-facts`**: the "names-only grounding" caveat now prints only when grounding is actually names-only; native platforms note that an empty `capabilities` list reflects TypeScript-first capability authoring, not lack of SDK support.
|
|
75
|
+
- **Design contract** confirmation re-routes to `needs-confirmation` when the preview is absent; the design reference inlines only sanitized `:root` token declarations, never raw source.
|
|
76
|
+
- Concrete CLI bugs from the first sweep (broken docs path, `engagement` show/init path mismatch, `workplan.json` persistence, and related discovery/intake edges).
|
|
77
|
+
|
|
78
|
+
### Compatibility
|
|
79
|
+
- **No exit-code or sidecar-*format* breaking changes.** The `completeness` / `selectedOptionalCapabilities` fields added to `vise status` / the init `findings.json` snapshot, and the new `sp-vise/baseline.json` artifact, are all **additive**; the `test:sidecar-compat` baseline (frozen 1.1.0 sidecar, no baseline.json) stays green. The rule corpus and contract digest are unchanged, so existing attestations are not invalidated. `vise check` with no flags is unchanged — the brownfield baseline only applies under the explicit `--new-only` flag.
|
|
80
|
+
|
|
7
81
|
## 1.2.0 — 2026-06-18
|
|
8
82
|
|
|
9
83
|
Adds advisory **solution-path / UIKit routing** and a fail-closed fix to the SwiftPM manifest sensor. No change to `vise check` exit codes, compliance rules, or sidecar **formats**; the one behavior change is the SwiftPM-timeout outcome noted under Changed.
|
|
@@ -594,8 +668,7 @@ The design, completeness, and SDK-version layers are **advisory** — they infor
|
|
|
594
668
|
- **agy + codex runners** (`run-agy-cells.sh`, `run-codex-cells.sh`) — production-quality scripts with TTY-detection fixes and workspace isolation.
|
|
595
669
|
|
|
596
670
|
### Findings & reports
|
|
597
|
-
-
|
|
598
|
-
- `benchmarks/MARKETING.html` — three-tier marketing-claim framework (safe / concrete / honest / aspirational) with supporting wallclock data and a list of metrics to instrument next.
|
|
671
|
+
- Historical generated HTML reports captured the benchmark methodology, results, and marketing-claim framework for this round. They were later removed from source control during the 1.4.0 benchmark cleanup; retained summaries now live in Markdown result files.
|
|
599
672
|
|
|
600
673
|
### Honest claim
|
|
601
674
|
On 9 new SDK domain implementations with codex gpt-5.4, vise+skill produced 7 working features vs 3 for pure MCP — same agent, same prompts. The cost: +28% wallclock per session. The net: −52% wallclock per *working* feature, because more features ship on the first try. Vise consistently catches five bug classes that capable models otherwise miss: wrong DM channel type, missing push register/unregister lifecycle, one-shot queries where live subscriptions are required, missing ban checks before write operations, and missing flag affordances on user-generated content.
|
package/README.md
CHANGED
|
@@ -77,7 +77,7 @@ vise install-skill --target copilot . # GitHub Copilot / VS Code
|
|
|
77
77
|
# "Add a social feed to this app using the social.plus SDK."
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
The skill drives the loop automatically — `vise inspect` → `vise plan` → `vise init` → edit code → `vise check` → `vise run-sensors`. You drive intent, answer scope questions, and
|
|
80
|
+
The skill drives the loop automatically — `vise inspect` → `vise plan` → `vise init` → edit code → `vise check` → `vise run-sensors`. You drive intent, answer scope questions, and **sign off the blueprint** (what gets built) before the agent writes a line; Vise keeps the agent honest. For dogfood or release proof, also launch the app and capture runtime evidence; static checks do not replace seeing the surface run. See [How it works](#how-it-works).
|
|
81
81
|
|
|
82
82
|
All skill targets:
|
|
83
83
|
|
|
@@ -98,11 +98,12 @@ Prefer a per-project install? `npm install -D @amityco/social-plus-vise`, then c
|
|
|
98
98
|
## How it works
|
|
99
99
|
|
|
100
100
|
1. **Inspect** — `vise inspect` detects the platform, app surfaces, available sensors, and design signals from the local repo.
|
|
101
|
-
2. **Plan** — `vise plan --request "..."` classifies the outcome, cites docs, and raises blocking intake and design-preview questions. Use `--summary` when you only need the route/intake readout before implementation. The agent surfaces questions; you answer.
|
|
102
|
-
3. **Initialize** — `vise init` writes the `sp-vise/` compliance contract.
|
|
101
|
+
2. **Plan** — `vise plan --request "..."` classifies the outcome, cites docs, and raises blocking intake and design-preview questions. If the request is too vague to classify or names a capability the SDK doesn't support, it returns a structured **clarify** block instead of guessing; for a broad goal it expands the outcome into a **blueprint** — the surfaces and experience it proposes to build. Use `--summary` when you only need the route/intake readout before implementation. The agent surfaces questions; you answer.
|
|
102
|
+
3. **Initialize** — `vise init` writes the `sp-vise/` compliance contract. For a **multi-surface build** (a journey spanning more than one surface), it first makes you **sign off the blueprint**: the *what* — the solution path (`sdk` / `uikit` / `hybrid`) and the experience/surfaces to build. This is the **alignment gate** — *"are we building the right thing?"* — the human-judgment counterpart to the deterministic compliance gate (*"did we build it the right way?"*) in step 5. `init` refuses and exits 7 until the request is resolved: `status: "needs-clarification"` when intake is unanswered or the request can't be classified, and `status: "needs-blueprint-confirmation"` until the blueprint is signed (`--answer blueprint_confirmation=<digest>`). The sign-off can't be bypassed, and it re-arms if the path, journey, or design source later changes.
|
|
103
103
|
4. **Build** — the agent edits your code, grounded by `vise search-docs` and `vise get-doc-page`.
|
|
104
104
|
5. **Check & repair** — `vise check` reports deterministic findings, completeness gaps, and attestation needs. The agent fixes findings or records attestations with evidence, looping until green.
|
|
105
105
|
6. **Sense** — `vise run-sensors` runs your project's own typecheck/build/lint/SDK smokes. Done means the contract and evidence are committed, not just that the agent stopped.
|
|
106
|
+
7. **Prove runtime readiness** — for dogfood, release, or any user-visible handoff, ask before spending browser/simulator/emulator/device resources. If approved, boot the actual target, capture screenshots/logs, and record what data was discovered or created at runtime. Discover targets naturally from host app state, SDK queries, user selection, or SDK create-flow return values; if the tenant has no data, ask whether to prepare Console data or seed safe dogfood data before claiming populated proof. When a `sp-vise/smoke.json` contract exists, run `vise smoke` against captured logs; `expect: "populated"` requires `loaded count=N` with `N > 0`. If runtime proof is declined or a completed native output cannot be archived, say so explicitly; starter launch proof is useful, but it is not proof that the completed social.plus surface ran.
|
|
106
107
|
|
|
107
108
|
### Solution path & UIKit routing (advisory)
|
|
108
109
|
|
|
@@ -122,17 +123,19 @@ The layer is set by the *kind of claim*, which is how Vise is designed to avoid
|
|
|
122
123
|
|
|
123
124
|
Correctness is gated by deterministic rules or attestations; completeness is gated by explicit scope decisions; conformance stays advisory because "matches the brand" is legitimately subjective. Each gating rule is itself mutation-verified — its fix is reverted to confirm the check actually fails without it, so a rule that can't fail is removed rather than shipped as theater. `vise explain <ruleId>` prints any rule's rationale, evidence requirements, and remediation.
|
|
124
125
|
|
|
126
|
+
Runtime proof is a separate evidence layer. `vise check` and `vise run-sensors` can prove structure, completeness, and local build commands, but they cannot prove that the selected community/feed/chat route renders on a cold launch. Ask before running browser or native runtime proof because it can consume local resources and agent tokens. If the user declines, state the expected limitation: cold-launch session races, empty tenant data, route wiring, permissions, and native packaging remain unproven. Use `vise smoke` where the app declares a runtime-smoke contract.
|
|
127
|
+
|
|
125
128
|
**Supported outcomes:** feed · comments · chat · moderation · community · social graph (follow) · in-app notifications · plus setup (SDK, push, live data). `vise plan`/`init` classify the request and tailor the plan, rules, and feature checklist.
|
|
126
129
|
|
|
127
130
|
### Engagement Intelligence
|
|
128
131
|
|
|
129
|
-
**Advisory, in preview.** The three layers above answer *whether you built it right*. Ahead of the build, Vise can also help reason about *what to build*: an **Engagement Intelligence** layer turns a product goal into multiple candidate **engagement strategies** — archetypes, UX patterns, and solution variants drawn from a social.plus experience catalog — with rationale, tradeoffs, no-fit guidance, availability boundaries, and review gaps. The human or driving agent still chooses the direction, then Vise compiles that selected variant into an implementation plan (`vise creative` → `vise creative accept` → `vise experience compile`), optionally bridging to installable social.plus blocks, plus advisory UX expectations and a multi-dimension experience review.
|
|
132
|
+
**Advisory, in preview.** The three layers above answer *whether you built it right*. Ahead of the build, Vise can also help reason about *what to build*: an **Engagement Intelligence** layer turns a product goal into multiple candidate **engagement strategies** — archetypes, UX patterns, and solution variants drawn from a social.plus experience catalog — with rationale, tradeoffs, no-fit guidance, availability boundaries, and review gaps. The driving agent presents the EI choice as a visible decision — recommended experience, concrete fit signals, credible alternatives, tradeoffs, expected blueprint surfaces, and no-fit option — before it accepts a variant. The human or driving agent still chooses the direction, then Vise compiles that selected variant into an implementation plan (`vise creative` → `vise creative accept` → `vise experience compile`), optionally bridging to installable social.plus blocks, plus advisory UX expectations and a multi-dimension experience review.
|
|
130
133
|
|
|
131
134
|
It is **local-only, never uploads, carries no calibrated score**, and **never changes `vise check`'s exit codes**. The opt-in ranking preview is review context, not a top-1 confidence claim or autonomous product-strategy selector. Use it to shape the work; the validation layers still decide when it's done.
|
|
132
135
|
|
|
133
136
|
### Design contracts
|
|
134
137
|
|
|
135
|
-
Vise can ingest your aesthetic from an HTML/CSS prototype (`vise design extract`) or from the host app's own design system across web, Android, Flutter, and iOS (`vise design extract --from-project`). The contract is **advisory input for generation**, never an enforcement gate, and it feeds forward into plans only after you confirm the generated preview with `--answer design_contract_confirmation=yes
|
|
138
|
+
Vise can ingest your aesthetic from an HTML/CSS prototype (`vise design extract`) or from the host app's own design system across web, Android, Flutter, and iOS (`vise design extract --from-project`). The contract is **advisory input for generation**, never an enforcement gate, and it feeds forward into plans only after you confirm the generated preview with `--answer design_contract_confirmation=yes` — and on a multi-surface blueprint that confirmation is folded into the single blueprint sign-off, so you approve the design once for the whole journey rather than per surface. For social.plus-specific styling, `vise design init-tokens` scaffolds a dedicated, customer-editable token file (`src/styles/social-plus-tokens.css`) — edit it, re-extract, and future builds inherit the palette with no agent in the loop.
|
|
136
139
|
|
|
137
140
|
## Evidence
|
|
138
141
|
|
|
@@ -169,12 +172,13 @@ Each platform has dozens of rules across 10 compliance domains (feed, comments,
|
|
|
169
172
|
|
|
170
173
|
## CLI Reference
|
|
171
174
|
|
|
172
|
-
Run `vise <command> --help` for full flags. JSON output is the default for agent-facing commands.
|
|
175
|
+
Run `vise <command> --help` for full flags. JSON output is the default for agent-facing commands; the read commands (`check`, `status`, `plan`, `doctor`, `explain`, `explore`) also accept `--format human` for a readable summary.
|
|
173
176
|
|
|
174
177
|
### Inspect, plan, initialize
|
|
175
178
|
|
|
176
179
|
| Command | Purpose |
|
|
177
180
|
|---|---|
|
|
181
|
+
| `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 |
|
|
178
182
|
| `vise doctor` | Verify install; print version, install path, docs source |
|
|
179
183
|
| `vise inspect [path]` | Detect platform, monorepo surfaces, design signals, available sensors |
|
|
180
184
|
| `vise plan [path] --request "..." [--summary]` | Grounded implementation plan with intake questions and docs citations; `--summary` prints a compact route/intake view |
|
|
@@ -184,13 +188,14 @@ Run `vise <command> --help` for full flags. JSON output is the default for agent
|
|
|
184
188
|
| `vise workplan next [path] --request "..."` | For broad social requests: print the next uncompleted surface and its focused commands |
|
|
185
189
|
| `vise workplan status [path] --request "..."` | Show the workplan sequence and completed surfaces |
|
|
186
190
|
| `vise workplan complete [path] --request "..." --surface <id>` | Record a green-checked surface; snapshots evidence under `sp-vise/workplan-snapshots/<surface>/` |
|
|
191
|
+
| `vise workplan trim [path] --request "..." --surface <id> --reason "..."` | Deliberately omit a companion surface (surface-level scope-omit). `--reason` required; re-arms the blueprint sign-off gate (re-sign the trimmed blueprint before proceeding) |
|
|
187
192
|
|
|
188
193
|
### Creative pre-planning (advisory)
|
|
189
194
|
|
|
190
195
|
| Command | Purpose |
|
|
191
196
|
|---|---|
|
|
192
197
|
| `vise creative [path] --request "..." [--requirements <path\|none>] [--prototype <html>] [--ranking-preview]` | Write an advisory Engagement Intelligence brief with multiple candidate solution variants, rationale, tradeoffs, and review gaps; `--ranking-preview` adds opt-in, local-only review context that never reorders the default candidates |
|
|
193
|
-
| `vise creative accept [path] --variant <id
|
|
198
|
+
| `vise creative accept [path] --variant <id> --rationale "..." --confidence high\|medium\|low` | Record the grounded selected variant so `plan`/`init`/`workplan` carry it forward; `--variant none --rationale "..." --confidence high\|medium\|low` records a catalog-gap signal instead |
|
|
194
199
|
| `vise ux-harness [path]` | Generate advisory UX expectations from the accepted selection |
|
|
195
200
|
| `vise experience compile [path]` | Compile the accepted variant into an implementation artifact plan |
|
|
196
201
|
| `vise experience sensors [path]` | Write an advisory multi-dimension sensor framework (no calibrated score) |
|
|
@@ -206,7 +211,8 @@ Everything in this group is local and advisory: no uploads, no `vise check` exit
|
|
|
206
211
|
|---|---|
|
|
207
212
|
| `vise design extract <prototypePath> [--repo .] [--no-write]` | Extract a graded design contract + visual preview from an HTML/CSS prototype |
|
|
208
213
|
| `vise design extract --from-project [path] [--no-write]` | Derive the contract from the project's own design system: CSS custom properties (incl. shadcn/Tailwind v4 `@theme`), TS/JS token modules, Android `colors.xml`/`dimens.xml`, Flutter `Color(0x…)`, iOS `.colorset`/Swift colors |
|
|
209
|
-
| `vise design check [path]` | Advisory token-conformance report; never fails a build |
|
|
214
|
+
| `vise design check [path]` | Advisory token-conformance report (incl. computed WCAG for the brand palette's role pairs when a profile exists); never fails a build |
|
|
215
|
+
| `vise design contrast <foreground> <background>` | Compute the WCAG 2.x contrast ratio between two colours (advisory) — check any text/icon colour that isn't a palette role instead of eyeballing it |
|
|
210
216
|
| `vise design preview [path] [--reference <prototype>]` | Write a self-contained visual review (`sp-vise/design-preview.html`) for human/VLM judgment |
|
|
211
217
|
| `vise design reference [path] [--title <name>]` | Write a self-contained design-system spec: swatches, type samples, component demos |
|
|
212
218
|
| `vise design init-tokens [path] [--force]` | Scaffold `src/styles/social-plus-tokens.css` (greenfield defaults or seeded from existing tokens); idempotent |
|
|
@@ -225,6 +231,8 @@ Everything in this group is local and advisory: no uploads, no `vise check` exit
|
|
|
225
231
|
|---|---|
|
|
226
232
|
| `vise check [path]` | Re-validate against the recorded contract: `green`, `needs-attestation`, `deterministic-failures`, `blocked`, or `contract-drift` |
|
|
227
233
|
| `vise check [path] --ci` | Read-only variant that exits non-zero unless green (for CI) |
|
|
234
|
+
| `vise check [path] --new-only` | **Brownfield gate.** With a recorded baseline, gate only on findings introduced *since* the baseline (pre-existing ones are reported but excluded). Default `check` always gates on everything |
|
|
235
|
+
| `vise baseline [path]` | Snapshot the current pre-existing findings to `sp-vise/baseline.json` so `check --new-only` can separate legacy debt from new gaps. `vise init --baseline` records it at init time |
|
|
228
236
|
| `vise validate [path]` | Run the deterministic validators only (no attestation comparison) |
|
|
229
237
|
| `vise sync [path]` | Persist deterministic-pass evidence to `sp-vise/attestations/` |
|
|
230
238
|
| `vise attest [path] --rule <id> --signer host-agent --confidence high --evidence-file evidence.json --rationale "..."` | Record an attestation when a rule passes through architecture the deterministic check can't see |
|
|
@@ -236,6 +244,7 @@ Everything in this group is local and advisory: no uploads, no `vise check` exit
|
|
|
236
244
|
| Command | Purpose |
|
|
237
245
|
|---|---|
|
|
238
246
|
| `vise run-sensors [path] [--dry-run]` | Run detected project scripts (npm, Gradle, Flutter, lint, typecheck, SDK smokes); `--dry-run` lists without executing |
|
|
247
|
+
| `vise smoke [path] --log <file>` | Assess a captured runtime mount-smoke log into a pass/fail verdict + record evidence. `expect: "populated"` requires `loaded count=N` with `N > 0`; this catches the session-establish and empty-data gaps `vise check` can't see (see [docs/RUNTIME_SMOKE.md](docs/RUNTIME_SMOKE.md)) |
|
|
239
248
|
| `vise install-skill --target <host>` | Install the bundled skill into a coding host (see [Quick Start](#quick-start)) |
|
|
240
249
|
| `vise print-skill` | Print the skill markdown to stdout |
|
|
241
250
|
| `vise engagement init [path] [--tier ...] [--customer-id ...] [--scope ...]` | Record optional contractual scope metadata |
|
|
@@ -257,7 +266,7 @@ MCP-capable hosts can call Vise as structured tool calls instead of shell comman
|
|
|
257
266
|
}
|
|
258
267
|
```
|
|
259
268
|
|
|
260
|
-
Tool names (snake_case per MCP convention): `inspect_project`, `creative_brief`, `creative_accept`, `ux_harness`, `compile_experience`, `experience_sensors`, `plan_harness`, `plan_integration`, `init_compliance`, `check_compliance`, `experience_report`, `record_learning`, `show_learning`, `sync_compliance`, `attest_rule`, `explain_rule`, `init_engagement`, `show_engagement`, `search_docs`, `get_doc_page`, `debug_issue`, `validate_setup`, `run_sensors`, `design_extract`, `design_check`, `design_preview`, `design_reference`, `design_init_tokens`.
|
|
269
|
+
Tool names (snake_case per MCP convention): `inspect_project`, `creative_brief`, `creative_accept`, `ux_harness`, `compile_experience`, `experience_sensors`, `plan_harness`, `plan_integration`, `init_compliance`, `check_compliance`, `experience_report`, `record_learning`, `show_learning`, `sync_compliance`, `attest_rule`, `explain_rule`, `init_engagement`, `show_engagement`, `search_docs`, `get_doc_page`, `debug_issue`, `validate_setup`, `run_sensors`, `design_extract`, `design_check`, `design_contrast`, `design_preview`, `design_reference`, `design_init_tokens`.
|
|
261
270
|
|
|
262
271
|
These mirror the CLI commands above. The adapter still answers the legacy `resolve_request` and `suggest_patch` names, but they are deprecated in favour of `plan_integration` plus host-tool edits.
|
|
263
272
|
|
|
@@ -310,15 +319,19 @@ Vise writes local planning, compliance, design, and evidence artifacts under `sp
|
|
|
310
319
|
| `sp-vise/creative-brief.json` + `creative-brief.md` | `vise creative` | Advisory brief: goals, archetypes, candidate variants (JSON + human-readable) |
|
|
311
320
|
| `sp-vise/candidate-ranking-preview.json` | `vise creative --ranking-preview` | Opt-in local ranking preview for review context; `experience_score: null`, no uploads, no default-order change, no top-1 confidence claim |
|
|
312
321
|
| `sp-vise/creative-selection.json` | `vise creative accept` | Accepted variant and plan/workplan feed-forward context |
|
|
313
|
-
| `sp-vise/catalog-gap.json` | `vise creative accept --variant none` | Local-only no-fit signal for human catalog review |
|
|
322
|
+
| `sp-vise/catalog-gap.json` | `vise creative accept --variant none --rationale "..." --confidence high\|medium\|low` | Local-only no-fit signal for human catalog review |
|
|
314
323
|
| `sp-vise/ux-harness.json` | `vise creative accept` or `vise ux-harness` | Advisory UX pattern expectations and anti-patterns |
|
|
315
324
|
| `sp-vise/experience-compiler.json` | `vise experience compile` | Advisory implementation plan: install guidance, surfaces, validation commands |
|
|
316
325
|
| `sp-vise/experience-sensors.json` | `vise experience sensors` | Advisory sensor framework; `score: null` until calibrated |
|
|
317
326
|
| `sp-vise/experience-report.json` | `vise experience-report` | Advisory dimensioned review; `score: null` until calibrated |
|
|
318
327
|
| `sp-vise/learning-events.jsonl` | `vise learning record` | Append-only, local-only learning event log |
|
|
319
328
|
| `sp-vise/learning-summary.json` | `vise learning record` | Derived summary; `recommendationOptimization.status: "not-active"` |
|
|
329
|
+
| `sp-vise/flow.json` | `vise workplan next` / `trim` | Entry-state, selected solution path, active blueprint digest, sign-off state, and omitted companion surfaces |
|
|
330
|
+
| `sp-vise/flow-blueprint.html` | `vise workplan next` | Human-readable blueprint preview for the alignment gate; review before passing `blueprint_confirmation=<digest>` |
|
|
320
331
|
| `sp-vise/workplan.json` | `vise workplan complete` | Broad-request progress: completed surfaces, green-check evidence |
|
|
321
332
|
| `sp-vise/workplan-snapshots/<surface>/` | `vise workplan complete` | Per-surface snapshots so later focused surfaces don't erase earlier proof |
|
|
333
|
+
| `sp-vise/smoke.json` | project/runtime harness | Declared runtime-smoke surfaces and expected resolution states |
|
|
334
|
+
| `sp-vise/evidence/runtime-smoke.json` | `vise smoke` | Captured runtime-smoke verdicts used by evidence-citing runtime rules |
|
|
322
335
|
| `sp-vise/design-contract.json` | `vise design extract` | Extracted tokens, breakpoints, source digests, stable design digest |
|
|
323
336
|
| `sp-vise/design-preview.html` | `vise design extract` / `preview` | Self-contained visual review; open before answering `design_contract_confirmation` |
|
|
324
337
|
| `sp-vise/design-reference.html` | `vise design reference` | Self-contained design-system spec (swatches, type, components) |
|
package/dist/capabilities.js
CHANGED
|
@@ -96,6 +96,17 @@ export const CAPABILITIES = [
|
|
|
96
96
|
symbols: [/AmityRoomRepository/i, /\bcreateRoom\b/, /createRoomAndStartStreaming/i, /getBroadcastData/i, /createLiveStreamPost/i, /\bgoLive\b/i, /startPublish/i],
|
|
97
97
|
hint: "live rooms/broadcasting via AmityRoomRepository (createRoom, go-live, live-viewing); post the stream with createLiveStreamPost (distinct from rendering a livestream post in the feed)",
|
|
98
98
|
},
|
|
99
|
+
{
|
|
100
|
+
id: "comment-preview",
|
|
101
|
+
label: "Comment preview on posts",
|
|
102
|
+
outcomes: ["add-feed"],
|
|
103
|
+
symbols: [
|
|
104
|
+
/\bgetComments\b/, /\bqueryComments\b/, /CommentRepository/i, /AmityCommentQueryBuilder/,
|
|
105
|
+
/\bgetCommentCount\b/, /\bgetLocalCommentCount\b/, /\bgetLatestComments\b/,
|
|
106
|
+
/\bcomments?Count\b/, /\blocalCommentCount\b/, /\blatestComments?(?:Ids?)?\b/,
|
|
107
|
+
],
|
|
108
|
+
hint: "Present a comment preview on each post: the comment count + a top-comment snippet + a tap-through to the thread. Read it off the post (commentsCount / latestComments) or query via getComments / CommentRepository. (The full thread + composer is the deeper add-comments work.) A genuinely comment-less feed (broadcast / announcement / a profile post-grid) opts out: `// vise: scope-omit comment-preview — <reason>`.",
|
|
109
|
+
},
|
|
99
110
|
{
|
|
100
111
|
id: "comments",
|
|
101
112
|
label: "Comment thread (list + composer)",
|
|
@@ -504,6 +515,23 @@ export const SHARED_PRODUCT_EXPECTATIONS = [
|
|
|
504
515
|
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
505
516
|
hint: "source unread badges from the SDK stream instead of counting stale local arrays",
|
|
506
517
|
},
|
|
518
|
+
{
|
|
519
|
+
id: "feed.post-body-rendering",
|
|
520
|
+
label: "Post body rendering",
|
|
521
|
+
outcomes: ["add-feed"],
|
|
522
|
+
kind: "shared-expectation",
|
|
523
|
+
availability: [
|
|
524
|
+
{
|
|
525
|
+
label: "SDK text post/body accessors",
|
|
526
|
+
symbols: [
|
|
527
|
+
/\b(?:text|description|caption)\b/i,
|
|
528
|
+
/\b(?:getData|getText|AmityTextPost|AmityPostData)\b/i,
|
|
529
|
+
],
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
533
|
+
hint: "render the post body/description/caption when present; a title field is optional and postId should not be the primary card content",
|
|
534
|
+
},
|
|
507
535
|
{
|
|
508
536
|
id: "feed.rich-post-rendering",
|
|
509
537
|
label: "Rich post rendering",
|
|
@@ -1144,7 +1172,7 @@ function symbolHaystack(symbols) {
|
|
|
1144
1172
|
}
|
|
1145
1173
|
const ADVISORY_NOTE = "Build each missing capability, or opt out with a recorded reason: `// vise: scope-omit <id> — <reason>`. A scope-omit marker without a reason is invalid and still counts as missing. Missing capabilities that are neither built nor validly opted-out cause `vise check` to exit with status `completeness-gap` (exit code 5).";
|
|
1146
1174
|
export const BASELINE_CAPABILITY_IDS_BY_OUTCOME = {
|
|
1147
|
-
"add-feed": ["pagination"],
|
|
1175
|
+
"add-feed": ["pagination", "comment-preview"],
|
|
1148
1176
|
"add-comments": ["comment-composer"],
|
|
1149
1177
|
"add-chat": ["send-message", "read-state"],
|
|
1150
1178
|
"add-follow": ["followers-following"],
|
|
@@ -1256,6 +1284,7 @@ export function assessSelectedOptionalCapabilities(source, outcome, selectedIds
|
|
|
1256
1284
|
note: "Selected optional capabilities are enforced only after the user or host agent opts in through `feed_optional_capabilities`. They are source sensors, not baseline compliance rules.",
|
|
1257
1285
|
};
|
|
1258
1286
|
}
|
|
1287
|
+
const MIN_SCOPE_OMIT_REASON_CHARS = 8;
|
|
1259
1288
|
export function assessCompleteness(source, outcome) {
|
|
1260
1289
|
const caps = baselineCapabilities(outcome);
|
|
1261
1290
|
const optOuts = new Map();
|
|
@@ -1265,12 +1294,14 @@ export function assessCompleteness(source, outcome) {
|
|
|
1265
1294
|
while ((match = omitPattern.exec(source)) !== null) {
|
|
1266
1295
|
const id = match[1].toLowerCase();
|
|
1267
1296
|
const reason = (match[2] ?? "").trim();
|
|
1268
|
-
if (reason) {
|
|
1297
|
+
if (reason.length >= MIN_SCOPE_OMIT_REASON_CHARS) {
|
|
1269
1298
|
optOuts.set(id, reason);
|
|
1270
1299
|
invalidOptOuts.delete(id);
|
|
1271
1300
|
}
|
|
1272
1301
|
else if (!optOuts.has(id)) {
|
|
1273
|
-
invalidOptOuts.set(id,
|
|
1302
|
+
invalidOptOuts.set(id, reason.length === 0
|
|
1303
|
+
? "scope-omit marker must include a reason"
|
|
1304
|
+
: `scope-omit reason is too short ("${reason}") — give an auditable reason of at least ${MIN_SCOPE_OMIT_REASON_CHARS} characters`);
|
|
1274
1305
|
}
|
|
1275
1306
|
}
|
|
1276
1307
|
const present = [];
|
|
@@ -1292,7 +1323,7 @@ export function assessCompleteness(source, outcome) {
|
|
|
1292
1323
|
missing.push({
|
|
1293
1324
|
id: cap.id,
|
|
1294
1325
|
label: cap.label,
|
|
1295
|
-
hint: invalidReason ? `${cap.hint};
|
|
1326
|
+
hint: invalidReason ? `${cap.hint}; ${invalidReason}` : cap.hint,
|
|
1296
1327
|
});
|
|
1297
1328
|
}
|
|
1298
1329
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export const ENTRY_STATE_ADVISORY = "This is an advisory entry-state classification. It does not change outcome classification, compliance rules, the sidecar schema, or `vise check` exit codes.";
|
|
2
|
+
export function classifyPathDecidedness(input) {
|
|
3
|
+
const { solutionPath, hasExplicitPathAnswer } = input;
|
|
4
|
+
const rec = solutionPath.recommendation;
|
|
5
|
+
if (hasExplicitPathAnswer) {
|
|
6
|
+
if (rec === "uikit")
|
|
7
|
+
return "uikit";
|
|
8
|
+
if (rec === "hybrid")
|
|
9
|
+
return "hybrid";
|
|
10
|
+
return "sdk";
|
|
11
|
+
}
|
|
12
|
+
if (rec === "hybrid")
|
|
13
|
+
return "hybrid";
|
|
14
|
+
if (rec === "needs-decision")
|
|
15
|
+
return "conflict";
|
|
16
|
+
if (rec === "uikit")
|
|
17
|
+
return solutionPath.signals.uikit.length > 0 ? "uikit" : "undecided";
|
|
18
|
+
return solutionPath.signals.sdk.length > 0 ? "sdk" : "undecided";
|
|
19
|
+
}
|
|
20
|
+
export function classifyFeatureCompleteness(input) {
|
|
21
|
+
const { outcome, broadSocialRequest, multiSurface, creativeSelected } = input;
|
|
22
|
+
if (creativeSelected)
|
|
23
|
+
return "has-feature-ref";
|
|
24
|
+
if (outcome !== "unknown" && !broadSocialRequest)
|
|
25
|
+
return "has-feature-ref";
|
|
26
|
+
if (broadSocialRequest || multiSurface)
|
|
27
|
+
return "goal-only-broad";
|
|
28
|
+
return "exploring";
|
|
29
|
+
}
|
|
30
|
+
export function classifyDesignCompleteness(input) {
|
|
31
|
+
if (!input.mentionsDesign)
|
|
32
|
+
return "none";
|
|
33
|
+
return input.designSignalCount > 0 ? "has-design-ref" : "mentions-no-ref";
|
|
34
|
+
}
|
|
35
|
+
export function entryStageFor(d) {
|
|
36
|
+
if (d.feature === "exploring")
|
|
37
|
+
return "explore";
|
|
38
|
+
if (d.path === "undecided" || d.path === "conflict")
|
|
39
|
+
return "decide-path";
|
|
40
|
+
if (d.feature === "goal-only-broad")
|
|
41
|
+
return "clarify";
|
|
42
|
+
if (d.design === "mentions-no-ref")
|
|
43
|
+
return "clarify";
|
|
44
|
+
return "confirm";
|
|
45
|
+
}
|
|
46
|
+
export function classifyEntryState(input) {
|
|
47
|
+
const pathDecidedness = classifyPathDecidedness(input);
|
|
48
|
+
const featureCompleteness = classifyFeatureCompleteness(input);
|
|
49
|
+
const designCompleteness = classifyDesignCompleteness(input);
|
|
50
|
+
const entryStage = entryStageFor({
|
|
51
|
+
path: pathDecidedness,
|
|
52
|
+
feature: featureCompleteness,
|
|
53
|
+
design: designCompleteness,
|
|
54
|
+
});
|
|
55
|
+
const sdkCount = input.solutionPath.signals.sdk.length;
|
|
56
|
+
const uikitCount = input.solutionPath.signals.uikit.length;
|
|
57
|
+
const rationale = [
|
|
58
|
+
`path-decidedness: ${pathDecidedness} (solution-path ${input.solutionPath.recommendation}; ${sdkCount} sdk / ${uikitCount} uikit signal(s)${input.hasExplicitPathAnswer ? "; explicit answer" : ""}).`,
|
|
59
|
+
`feature-completeness: ${featureCompleteness} (outcome ${input.outcome}${input.broadSocialRequest ? "; broad" : ""}${input.multiSurface ? "; multi-surface" : ""}${input.creativeSelected ? "; creative variant accepted" : ""}).`,
|
|
60
|
+
`design-completeness: ${designCompleteness} (${input.mentionsDesign ? "design mentioned" : "no design mention"}; ${input.designSignalCount} in-repo design signal(s)).`,
|
|
61
|
+
`enters the flow at the "${entryStage}" stage.`,
|
|
62
|
+
];
|
|
63
|
+
return {
|
|
64
|
+
entryStage,
|
|
65
|
+
pathDecidedness,
|
|
66
|
+
featureCompleteness,
|
|
67
|
+
designCompleteness,
|
|
68
|
+
rationale,
|
|
69
|
+
advisoryOnly: ENTRY_STATE_ADVISORY,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const COMMUNITY_TOKEN = /\bcommunit(?:y|ies)\b/i;
|
|
2
|
+
const COMMUNITY_CONTENT_TOKEN = /\b(?:feed|posts?|timeline|wall|content|share|discuss(?:ion)?|stories)\b/i;
|
|
3
|
+
const COMMUNITY_EXPERIENCE_PHRASE = /\bcommunity\s+(?:experience|space|hub|home|page)\b/i;
|
|
4
|
+
const COMMUNITY_EXPERIENCE = {
|
|
5
|
+
id: "community",
|
|
6
|
+
variantId: "community-first",
|
|
7
|
+
matches: (request) => COMMUNITY_EXPERIENCE_PHRASE.test(request) || (COMMUNITY_TOKEN.test(request) && COMMUNITY_CONTENT_TOKEN.test(request)),
|
|
8
|
+
surfaces: [
|
|
9
|
+
{ id: "feed", tier: "required-for-coherence" },
|
|
10
|
+
{ id: "comments", tier: "recommended" },
|
|
11
|
+
{ id: "community", tier: "required-for-coherence" },
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
const MESSAGING_SIGNALS = [
|
|
15
|
+
/\b(?:direct|private|instant|encrypted|secure|one[\s-]?on[\s-]?one|one[\s-]?to[\s-]?one|1\s?[-:]\s?1|peer[\s-]?to[\s-]?peer)[\s-]+messag\w+\b/i,
|
|
16
|
+
/\b(?:messaging|messenger)\s+(?:experience|app|application|feature|inbox)\b/i,
|
|
17
|
+
/\b(?:dms?|direct[\s-]?messages?)\s+(?:feature|inbox|experience|system|thread|cent(?:er|re))\b/i,
|
|
18
|
+
];
|
|
19
|
+
const MESSAGING_EXPERIENCE = {
|
|
20
|
+
id: "messaging",
|
|
21
|
+
variantId: "messaging-first",
|
|
22
|
+
matches: (request) => MESSAGING_SIGNALS.some((re) => re.test(request)),
|
|
23
|
+
surfaces: [
|
|
24
|
+
{ id: "chat", tier: "required-for-coherence" },
|
|
25
|
+
{ id: "profile", tier: "recommended" },
|
|
26
|
+
{ id: "notifications", tier: "recommended" },
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
const DISCUSSION_SIGNALS = [
|
|
30
|
+
/\b(?:discussion|community|online|message|q\s?&\s?a|q&a|qanda)\s+(?:forums?|boards?)\b/i,
|
|
31
|
+
/\b(?:forums?|message\s+boards?|bulletin\s+boards?)\s+(?:feature|experience|for\b)/i,
|
|
32
|
+
/\bthreaded\s+discussions?\b/i,
|
|
33
|
+
/\bq\s?&\s?a\s+(?:community|forum|board|experience|platform)\b/i,
|
|
34
|
+
];
|
|
35
|
+
const DISCUSSION_EXPERIENCE = {
|
|
36
|
+
id: "discussion",
|
|
37
|
+
variantId: "knowledge-network",
|
|
38
|
+
surfaces: [
|
|
39
|
+
{ id: "feed", tier: "required-for-coherence" },
|
|
40
|
+
{ id: "comments", tier: "required-for-coherence" },
|
|
41
|
+
{ id: "community", tier: "recommended" },
|
|
42
|
+
],
|
|
43
|
+
matches: (request) => DISCUSSION_SIGNALS.some((re) => re.test(request)),
|
|
44
|
+
};
|
|
45
|
+
const CREATOR_SIGNALS = [
|
|
46
|
+
/\b(?:creator|influencer|content[\s-]?creators?)\s+(?:platform|econom\w+|hub|program|tools?|studio|community|app|application|experience|marketplace|network|portal|space)\b/i,
|
|
47
|
+
/\bcreator[\s-]?monetization\b/i,
|
|
48
|
+
/\bmonetiz\w+\s+(?:creators?|content|audiences?|fans?|subscribers?|followers?)\b/i,
|
|
49
|
+
];
|
|
50
|
+
const CREATOR_EXPERIENCE = {
|
|
51
|
+
id: "creator",
|
|
52
|
+
variantId: "creator-first",
|
|
53
|
+
surfaces: [
|
|
54
|
+
{ id: "feed", tier: "required-for-coherence" },
|
|
55
|
+
{ id: "profile", tier: "required-for-coherence" },
|
|
56
|
+
{ id: "comments", tier: "recommended" },
|
|
57
|
+
{ id: "livestream", tier: "recommended" },
|
|
58
|
+
],
|
|
59
|
+
matches: (request) => CREATOR_SIGNALS.some((re) => re.test(request)),
|
|
60
|
+
};
|
|
61
|
+
export const EXPERIENCE_BUNDLES = [
|
|
62
|
+
COMMUNITY_EXPERIENCE,
|
|
63
|
+
MESSAGING_EXPERIENCE,
|
|
64
|
+
DISCUSSION_EXPERIENCE,
|
|
65
|
+
CREATOR_EXPERIENCE,
|
|
66
|
+
];
|
|
67
|
+
export function experienceBundleFor(request) {
|
|
68
|
+
const text = typeof request === "string" ? request : "";
|
|
69
|
+
return EXPERIENCE_BUNDLES.find((bundle) => bundle.matches(text));
|
|
70
|
+
}
|
package/dist/explore.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { capabilityChecklist } from "./capabilities.js";
|
|
2
|
+
import { classifyOutcome, getOutcomeDefinition } from "./outcomes.js";
|
|
3
|
+
const DISCOVERY_MENU = [
|
|
4
|
+
"setup-sdk",
|
|
5
|
+
"add-feed",
|
|
6
|
+
"add-comments",
|
|
7
|
+
"add-chat",
|
|
8
|
+
"add-community",
|
|
9
|
+
"add-follow",
|
|
10
|
+
"add-moderation",
|
|
11
|
+
"add-notifications",
|
|
12
|
+
"setup-push",
|
|
13
|
+
"setup-live-data",
|
|
14
|
+
];
|
|
15
|
+
function outcomeBrief(outcome, platform, request) {
|
|
16
|
+
const def = getOutcomeDefinition(outcome);
|
|
17
|
+
return {
|
|
18
|
+
outcome,
|
|
19
|
+
summary: def.interpretation,
|
|
20
|
+
capabilities: capabilityChecklist(outcome).map((capability) => ({ id: capability.id, label: capability.label })),
|
|
21
|
+
docs: def.docs(platform).slice(0, 4).map((doc) => ({ path: doc.path, reason: doc.reason })),
|
|
22
|
+
start: `vise plan . --request ${JSON.stringify(request)}`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function exploreRequest(request, platform = "typescript") {
|
|
26
|
+
const matched = classifyOutcome(request);
|
|
27
|
+
const isKnown = matched !== "unknown" && DISCOVERY_MENU.includes(matched);
|
|
28
|
+
if (isKnown) {
|
|
29
|
+
return {
|
|
30
|
+
kind: "exploration",
|
|
31
|
+
request,
|
|
32
|
+
platform,
|
|
33
|
+
matched_outcome: matched,
|
|
34
|
+
routes: [outcomeBrief(matched, platform, request)],
|
|
35
|
+
also_available: DISCOVERY_MENU.filter((outcome) => outcome !== matched).map((outcome) => ({
|
|
36
|
+
outcome,
|
|
37
|
+
summary: getOutcomeDefinition(outcome).interpretation,
|
|
38
|
+
})),
|
|
39
|
+
note: "Discovery is pre-credentials and read-only — no project or API key needed. When you're ready to build, `vise plan`/`vise init` starts a tracked integration.",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
kind: "exploration",
|
|
44
|
+
request,
|
|
45
|
+
platform,
|
|
46
|
+
matched_outcome: null,
|
|
47
|
+
unmatched_note: "This request didn't map to a single social.plus outcome. Below is everything Vise can guide you through — pick one and run its `start` command.",
|
|
48
|
+
routes: DISCOVERY_MENU.map((outcome) => outcomeBrief(outcome, platform, request)),
|
|
49
|
+
note: "Discovery is pre-credentials and read-only — no project or API key needed. When you're ready to build, `vise plan`/`vise init` starts a tracked integration. If this is a broad social *product* (you're still shaping WHICH surfaces fit), run `vise creative <project> --request \"...\"` for an experience brief (ranked surface journeys) before committing to a single outcome.",
|
|
50
|
+
};
|
|
51
|
+
}
|