@amityco/social-plus-vise 0.12.5 → 0.13.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 CHANGED
@@ -4,6 +4,72 @@ 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.13.0 — 2026-06-03
8
+
9
+ **Theme:** Deterministic-gate soundness, CLI reliability, and post-rebrand coherence (driven by two repo reviews).
10
+
11
+ ### Fixed
12
+ - **Boolean flags now accept `--flag=true/false`.** `--ci=true`, `--dry-run=true`, `--force=true`, etc. were parsed as known flags but never detected, so `vise check --ci=true` silently ran in non-CI mode without erroring. Boolean flags now parse `=true/1/yes` → on and `=false/0/no` → off, and reject other values loudly.
13
+ - **`vise install-skill` supersedes pre-rebrand installs.** Installing removes a stale sibling `social-plus-foundry/` skill directory (and `social-plus-foundry.mdc` for `cursor-rules`) so hosts no longer serve old `spf`/foundry guidance alongside the current skill. Reported as `supersededLegacy` in the command output.
14
+ - **CLI no longer crashes on a missing tree-sitter native binding** — the parser loads lazily and degrades to regex-only instead of taking down every command (including doc lookup) at startup; affects platforms without prebuilt binaries (linux-arm64, Alpine/musl, win32-arm64).
15
+ - **Gating literal checks are comment-aware** — a commented-out or documented `channelId`/`apiKey` no longer trips a no-escape gate (a false positive that hard-failed CI with no attestation path). ts/tsx/kotlin use the tree-sitter stripper; Swift/Dart use a conservative string-aware scanner that only blanks comment spans.
16
+
17
+ ### Added
18
+ - **`vise_version`** in `sp-vise/compliance.json`, attestations, `engagement.json`, and the design contract — written alongside the retained `foundry_version` (backward-compatible alias; excluded from all digests, so existing contracts do not drift).
19
+
20
+ ### Changed
21
+ - **Docs/copy aligned to the `Vise` name:** README, skill, and the generated sidecar no longer reference a non-existent `sp-check` binary (use `vise check`); `run-sensors` safety wording corrected ("runs detected project scripts/wrappers; inspect with `--dry-run` before running in an untrusted project"); `RULES.md` gating semantics corrected — the exit code is driven by `advisory`/`attestation.allowed`, not `severity`.
22
+ - **README benchmark section recalibrated** to match the Commune paper: N=1 caveat moved up front, the deterministic-grader/circularity disclosed, the speculative "rework sessions" table removed, and the null bug-fix-benchmark result noted.
23
+
24
+ ---
25
+
26
+ ## 0.12.5 — 2026-06-02
27
+
28
+ **Theme:** Design token lifecycle — customers can maintain a dedicated social.plus token file independently from their main app, with no AI agent required for updates.
29
+
30
+ ### Added
31
+ - **`vise design init-tokens [path] [--force]`** — scaffolds `src/styles/social-plus-tokens.css` in the customer's project, the single editable source for social.plus feature styling. **Greenfield:** full `--sp-*` neutral defaults (color, typography, spacing, radius, shadow, motion, sizing, z-index, breakpoints). **Brownfield:** seeded from the project's existing concrete token values, namespaced as `--sp-*` with origin comments. Idempotent — never clobbers an existing file; `--force` to override. The token file lives in `src/` (ships with the app); `sp-vise/` holds only the contract (never ships).
32
+ - **Freshness check in `vise design check`** — hashes `source.inputs` files at extract time, stores as `source.input_digests` in the contract. On `design check`, current file hashes are compared; if any changed, an advisory `staleContract` field surfaces a nudge: *"Run `vise design extract --from-project` to refresh."* Never blocks; purely informational. Works identically across all platforms.
33
+
34
+ ---
35
+
36
+ ## 0.12.4 — 2026-06-02
37
+
38
+ **Theme:** Advisory rule model + honest benchmark methodology.
39
+
40
+ ### Added
41
+ - **Advisory rule flag** (`advisory: true` in rule YAML) — rules marked advisory surface in `vise check` output with `status: "advisory"` but never contribute to `exitCode` or `needs-attestation`. Use for checks where the right answer depends on tenant configuration Vise cannot observe.
42
+
43
+ ### Changed
44
+ - **`reactions.configured-name-used`** (all 5 platforms) downgraded to advisory. Rule fires on ~100% of correct apps (every tenant defaults to `"like"`) and was only clearable by a ritual comment. Version bumped to 2; existing compliance.json files will show contract-drift — run `vise sync` to update.
45
+
46
+ ### Benchmark
47
+ - Brand benchmark (Spotify Encore × social.plus community feed, Sonnet n=3): pure-mcp 0/3 behavioral compliance (avg 2.3 behavioral findings), vise-design 3/3 (0). Ban-state is the standout discriminator — missed by all pure-mcp agents, fixed by all vise-design agents through the iteration loop.
48
+ - Ambiguous-brief design test: vise-design 0 hex literals (all 3 seeds), pure-mcp 0/2/15 (high variance). Design loop is a variance-reduction tool.
49
+ - Grader now partitions findings into behavioral / file-presence / attestation-dialect; headline score is behavioral-only.
50
+
51
+ ---
52
+
53
+ ## 0.12.3 — 2026-06-02
54
+
55
+ **Theme:** Design harness graduation — complete token extraction, Circles-inspired visual reference.
56
+
57
+ ### Added
58
+ - **`vise design reference [path] [--title <name>]`** — generates a self-contained `sp-vise/design-reference.html` design-system spec: fixed sidebar with grouped nav (COLOR / TYPOGRAPHY / LAYOUT / SURFACE / EFFECTS), sticky topbar, section headers with display-font titles, monospace token-row lists for non-visual groups (motion, breakpoints, z-index), and component samples. Reads source CSS for live `var()` resolution; falls back to contract tokens for native projects (Android/Flutter/iOS correctly grouped by category with concrete values).
59
+ - **6 new token categories** — `fontWeight`, `lineHeight`, `letterSpacing`, `borderWidth`, `breakpoint`, `zIndex`. All name-gated to prevent false positives (bare integers, unitless decimals are ambiguous without the name signal).
60
+
61
+ ### Fixed (silent miscategorizations)
62
+ - `--fs-*` (e.g. `--fs-sm: 14px`) was categorized as "space" — now correctly "fontSize".
63
+ - `--border-width-*` (e.g. `--border-width-thin: 1px`) was categorized as "color" (the color-name regex matched `/border/`) — now correctly "borderWidth". Fix requires the borderWidth check to precede the color branch.
64
+ - `--bp-*` and `--ls-*` fell through to the LENGTH→space fallback — now correctly "breakpoint" and "letterSpacing".
65
+
66
+ ### Changed
67
+ - `renderDesignPreview` now includes sections for all 6 new categories so they aren't silently omitted from `vise design preview` output.
68
+ - `categorizeTokenModuleValue` explicitly excludes the new categories (CSS-only extraction — consistent with the existing opacity exclusion).
69
+ - Streamly seed-ui reference: **69 → 80 tokens**, zero "not extracted" tags in the generated HTML.
70
+
71
+ ---
72
+
7
73
  ## 0.12.2 — 2026-06-02
8
74
 
9
75
  **Maintenance / hygiene release.** No functional change from `0.12.1` — identical rules, validators, and CLI. This release exists to scrub an anonymized customer name from the bundled `CHANGELOG`; `0.12.0` and `0.12.1` (which contained it) were unpublished from npm. Use `0.12.2`.
package/README.md CHANGED
@@ -47,6 +47,22 @@ Instead of just providing a CLI or AI skills, Vise implements a technique called
47
47
 
48
48
  Vise acts as the foreman of this factory, wrapping your local coding agents in compliance guardrails when they integrate social.plus SDKs. It inspects your project, grounds the agent in hosted docs, enforces 300 platform-specific compliance rules, checks the generated UI against the customer's design system, surfaces the full SDK feature surface so nothing is silently dropped, and runs your project's own build/lint/typecheck sensors. **Your source code never leaves your machine.**
49
49
 
50
+ At a glance, Vise sits between the user's prompt and the agent's code changes. The agent still edits the app; Vise turns the request into a grounded plan, records the local contract, and keeps checking until the integration is ready to ship.
51
+
52
+ ```mermaid
53
+ flowchart LR
54
+ Prompt["User prompt<br/>Add a social.plus feature"] --> Skill["AI skill<br/>drives the loop"]
55
+ Skill --> Inspect["Inspect project<br/>platform, app surface,<br/>design signals"]
56
+ Inspect --> Plan["Plan<br/>outcome, docs,<br/>intake questions"]
57
+ Plan --> Design["Design + completeness<br/>tokens, feature checklist,<br/>explicit opt-outs"]
58
+ Design --> Build["Agent builds<br/>edits customer code locally"]
59
+ Build --> Check["Vise check<br/>SDK compliance gate"]
60
+ Check -->|findings| Build
61
+ Check --> Sensors["Sensors<br/>typecheck, build,<br/>lint, SDK smoke"]
62
+ Sensors -->|failures| Build
63
+ Sensors --> Done["Done<br/>sp-vise contract<br/>and evidence"]
64
+ ```
65
+
50
66
  | Layer | Purpose |
51
67
  |---|---|
52
68
  | **Skill** (`SKILL.md`) | Tells your AI agent when to inspect, plan, fetch docs, edit, validate, and attest |
@@ -59,7 +75,7 @@ Vise validates on three layers, and the layer is set by the *kind of claim* —
59
75
 
60
76
  | Layer | Claim | How | Enforcement |
61
77
  |---|---|---|---|
62
- | **SDK compliance** | "this is **wrong**" | 300 deterministic rules (session renewal, live-collection vs one-shot, no secret in logs, parent-child rendering, ban-state gating…) | **Hard gate** — `vise check` blocks until green or attested |
78
+ | **SDK compliance** | "this is **wrong**" | 300 deterministic rules (session renewal, live-collection vs one-shot, no secret in logs, parent-child rendering, ban-state gating…) | **Hard gate** — `vise check` blocks until green or attested. A small advisory subset surfaces as informational only and never blocks. |
63
79
  | **Design conformance** | "this **looks off**" | extract the customer's design system into a contract, then check token usage | **Advisory** — `vise design check`/`preview`; never fails a build |
64
80
  | **Feature completeness** | "this is **missing**" | Vise proposes the full SDK feature surface per outcome; the agent opts out of anything out of scope with a recorded reason | **Advisory** — surfaced in `vise plan`/`check`; never fails a build |
65
81
 
@@ -67,7 +83,9 @@ Only correctness is gated (it can be made FP-free); conformance and completeness
67
83
 
68
84
  ### Design-conformant UI
69
85
 
70
- Vise can ingest the customer's aesthetic into a **design contract** and guide generation to match it — from an HTML/CSS prototype (`vise design extract`) or from the host app's own design system across web + Android + Flutter + iOS (`vise design extract --from-project`: CSS vars/Tailwind/token modules, `colors.xml`, Flutter `Color(0x…)`, iOS `.colorset`/Swift). `vise design check` reports token conformance; `vise design preview` writes a visual review. All advisory.
86
+ Vise can ingest the customer's aesthetic into a **design contract** and guide generation to match it — from an HTML/CSS prototype (`vise design extract`) or from the host app's own design system across web + Android + Flutter + iOS (`vise design extract --from-project`: CSS vars/Tailwind/token modules, `colors.xml`, Flutter `Color(0x…)`, iOS `.colorset`/Swift). `vise design check` reports token conformance; `vise design preview` writes a visual review; `vise design reference` generates a full visual design-system spec (swatches, type samples, component demos). All advisory.
87
+
88
+ **For social.plus-specific styling:** `vise design init-tokens` scaffolds `src/styles/social-plus-tokens.css` in your project — a dedicated token file for social.plus features that you can edit independently from your main app's design system. Greenfield projects get sensible `--sp-*` defaults; brownfield projects get their existing token values seeded in. Edit the file, run `vise design extract --from-project` to refresh the contract, and future agent builds inherit the updated palette — no AI agent needed in the update loop.
71
89
 
72
90
  ### Supported integrations (outcomes)
73
91
 
@@ -81,8 +99,8 @@ A bench vise holds the workpiece steady so the craftsman's hands are free to sha
81
99
 
82
100
  ## Benchmark: Phase 1 Results
83
101
 
84
- > **Every feature delivered correctly confirmed independently with two different AI coding tools.**
85
- > With Vise, both agents built all 9 social features with no production gaps. Without Vise, 3 out of 9 features had hidden problems that would only surface after users complained.
102
+ > **The compliance gaps agents ship on their own, they close under Vise's check loop.**
103
+ > Across two capable coding agents (Cursor / Composer 2.5 and Claude Sonnet 4.6), the features with *secondary* compliance requirements Chat, Moderation, Push failed without Vise and passed with it; both agents reached 9/9 with Vise. This is a **strong directional signal at N=1 per cell, not a settled statistical finding.** The [Commune paper](docs/commune-paper-2026-05-30.md) is the full, honest version — methodology, per-cell results, threats to validity, and a complementary bug-fix benchmark where Vise showed *no* advantage.
86
104
 
87
105
  ### What "delivered correctly" means
88
106
 
@@ -93,7 +111,7 @@ A bench vise holds the workpiece steady so the craftsman's hands are free to sha
93
111
  - **Moderation actions** (report, flag, block) are surfaced in the UI so users can act on them, not buried in a hook
94
112
  - **Chat and feed queries** use live, reactive subscriptions — not one-time fetches that go stale
95
113
 
96
- Without Vise, AI agents frequently implement the primary feature correctly but miss these secondary requirements. They know about them in the abstract — but when building a chat screen, "ban state" feels out of scope and gets skipped. `sp-check` turns that vague awareness into a specific, actionable finding.
114
+ Without Vise, AI agents frequently implement the primary feature correctly but miss these secondary requirements. They know about them in the abstract — but when building a chat screen, "ban state" feels out of scope and gets skipped. `vise check` turns that vague awareness into a specific, actionable finding.
97
115
 
98
116
  ### The experiment: three conditions, nine features
99
117
 
@@ -106,7 +124,7 @@ SDK setup · User presence · Social feed · Events · Chat & DMs · Push notifi
106
124
  |---|---|---|
107
125
  | **Pure MCP** | Access to social.plus docs only — no compliance guidance | Baseline: how well does the agent do on its own? |
108
126
  | **Rules-as-Markdown** | The full 1,013-line compliance rulebook pasted directly into the prompt | Is the problem just that the agent doesn't know the rules? |
109
- | **Vise + Skill** | Full Vise CLI — `sp-check` runs automatically, agent reads specific findings, fixes them, repeats until green | Does an active feedback loop change the outcome? |
127
+ | **Vise + Skill** | Full Vise CLI — `vise check` runs automatically, agent reads specific findings, fixes them, repeats until green | Does an active feedback loop change the outcome? |
110
128
 
111
129
  The Rules-as-Markdown condition is the key isolation: if the agent already knows all the rules, does giving it the spec document fix the problem? The answer turned out to be **no** — knowing the rules and being forced to act on specific findings are different things.
112
130
 
@@ -117,38 +135,28 @@ The Rules-as-Markdown condition is the key isolation: if the agent already knows
117
135
  | **Cursor (Composer 2.5)** | 6 out of 9 ✗ | 5 out of 9 ✗ | **9 out of 9 ✅** |
118
136
  | **Claude Code (Sonnet 4.6)** | 6 out of 9 ✗ | 7 out of 9 ✗ | **9 out of 9 ✅** |
119
137
 
120
- The three features that consistently fail without Vise — **Chat**, **Moderation**, and **Push Notifications** — are exactly the ones with secondary compliance requirements (ban-state, report affordances, Amity preference API). Vise's `sp-check` catches these with a specific finding; the rules doc does not.
121
-
122
- Both agents reached a perfect score with Vise. Neither could reach it with the compliance spec pasted into the prompt. All 9 passes were independently verified by code inspection — no scoring shortcuts.
138
+ The three features that consistently fail without Vise — **Chat**, **Moderation**, and **Push Notifications** — are exactly the ones with secondary compliance requirements (ban-state, report affordances, Amity preference API). `vise check` catches these with a specific finding; the rules doc does not.
123
139
 
124
- ### Efficiencyrework sessions needed
140
+ Both agents reached 9/9 with Vise. The Rules-as-Markdown arm did **not** reliably beat the plain-docs control 5/9 on Cursor (*below* control) and 7/9 on Sonnet — and at N=1 per cell neither gap is distinguishable from noise. The robust, reproducible signal is narrower and mechanistic: **Chat and Moderation never pass under either control arm, and always pass under Vise.** Passes were scored by a deterministic grader, not by hand — see [Reproducibility & honest caveats](#reproducibility--honest-caveats) for what that grader does and doesn't establish.
125
141
 
126
- Vise delivers all 9 features correctly in a single session. The other conditions leave failing features that require additional sessions to diagnose (the gap isn't visible without `sp-check`) and fix.
127
-
128
- | Coding agent (model) | Condition | Features correct | Rework sessions needed |
129
- |---|---|---|---|
130
- | **Cursor (Composer 2.5)** | Pure MCP | 6 / 9 ✗ | +3 or more |
131
- | **Cursor (Composer 2.5)** | Rules-as-Markdown | 5 / 9 ✗ | +4 or more |
132
- | **Cursor (Composer 2.5)** | **Vise + Skill** | **9 / 9 ✅** | **0 ✅** |
133
- | **Claude Code (Sonnet 4.6)** | Pure MCP | 6 / 9 ✗ | +3 or more |
134
- | **Claude Code (Sonnet 4.6)** | Rules-as-Markdown | 7 / 9 ✗ | +2 or more |
135
- | **Claude Code (Sonnet 4.6)** | **Vise + Skill** | **9 / 9 ✅** | **0 ✅** |
142
+ ### Why it matters
136
143
 
137
- <sub>Rework sessions are additional developer-initiated prompts needed after the initial session to diagnose and fix the failing features. Each failing feature typically requires at least one session to identify the gap and one to fix it and that's without the benefit of `sp-check` pointing directly at the problem.</sub>
144
+ A failing feature without Vise is *invisible* until a user hits it: the code compiles, the demo works, and the ban-state gap surfaces only when a banned user posts. Vise turns that latent gap into a specific finding the agent fixes before you ship. (We did not separately measure remediation effort, so this makes no rework-cost claim only that the gaps are real and silent without a checker.)
138
145
 
139
- ### Reproducibility
146
+ ### Reproducibility & honest caveats
140
147
 
141
- - **Gate-checked:** Every pass was verified by code inspection — the Vise workspaces contain an actual UI-level ban gate; the pure-MCP workspaces do not. Zero attestation shortcuts.
142
- - **Built from scratch** (greenfield seed)not patching existing code.
143
- - **Three arms run with separate tooling.** The Rules-as-Markdown arm has no `sp-check` tool available — it cannot "cheat" by running the checker.
144
- - **N=1 per cell (Phase 1).** Each agent ran each scenario once. Repeatability seeds on the three most discriminating slices (CM-CHAT, CM-MODERATE, CM-PUSH) are pending. These results should be treated as a strong initial signal, not a statistically settled finding.
145
- - Full per-feature scorecards, agent transcripts, and workspace diffs: [`benchmarks/FINDINGS.html`](benchmarks/FINDINGS.html) · [`benchmarks/RULES_AS_MARKDOWN.html`](benchmarks/RULES_AS_MARKDOWN.html)
148
+ - **Scoring is deterministic — and it overlaps with what Vise enforces.** Each cell is graded on four dimensions: `vise check --ci` (the same compliance ruleset), the project's own sensors (build / typecheck / lint), and hand-authored string-inclusion acceptance patterns. Because the metric overlaps Vise's own rules and only the Vise arm iterates against that checker read the headline as "Vise's checks pass," not as a fully independent oracle. The acceptance patterns are literal string matching (not AST), so they involve authoring judgment.
149
+ - **Vise-arm passes were deterministic-pass**, not attestation exceptions agents fixed the code. (The grader applies a narrow, *symmetric* auto-attestation for absence / type-stub findings across **all** arms including the controls; it cannot satisfy the acceptance patterns, so it does not tilt the result toward Vise.)
150
+ - **Three arms, separate tooling.** The Rules-as-Markdown arm has no Vise checker available — it cannot run `vise check`.
151
+ - **Built from scratch** (greenfield seed), capable models with prior SDK familiarity. A complementary **bug-fix** benchmark showed **no Vise advantage** the loop helps on greenfield integration, not local bug hunts.
152
+ - **N=1 per cell.** A strong directional signal (the Chat/Moderation/Push mechanism reproduces across both models), **not** a statistically settled finding; repeatability seeds are pending.
153
+ - **Full methodology, per-cell analysis, and threats to validity:** [the Commune paper](docs/commune-paper-2026-05-30.md). The [`benchmarks/FINDINGS.html`](benchmarks/FINDINGS.html) and [`benchmarks/RULES_AS_MARKDOWN.html`](benchmarks/RULES_AS_MARKDOWN.html) files are **summary report tables**, not raw transcripts or workspace diffs.
146
154
 
147
155
  ### Which mode should I use?
148
156
 
149
157
  | If you… | Use | Why |
150
158
  |---|---|---|
151
- | Building new social features with an AI agent | **Vise CLI + Skill** | The only mode that reliably delivers all features correctly |
159
+ | Building new social features with an AI agent | **Vise CLI + Skill** | The mode that closed every secondary-compliance gap in our benchmark |
152
160
  | Auditing existing social.plus code | `vise check --ci` | Grades any codebase against the full ruleset |
153
161
  | Enforcing compliance in a CI pipeline | `vise check --ci` | Exits non-zero on failures; structured JSON output for logs |
154
162
 
@@ -162,7 +170,7 @@ Vise delivers all 9 features correctly in a single session. The other conditions
162
170
  | **React Native** | ✅ Full | `tsc`, `npm lint`, SDK import smoke |
163
171
  | **Flutter / Dart** | ✅ Full | `flutter analyze`, `flutter test` |
164
172
  | **Android (Kotlin)** | ✅ Full | Gradle assemble, unit tests |
165
- | **iOS (Swift)** | ✅ Full | (static rule checks; runtime sensors WIP) |
173
+ | **iOS (Swift)** | ✅ Full | Static rule checks fully operational. Build sensor not wired (`xcodebuild` environment requirements make it fragile) — `vise run-sensors` returns no-sensors for iOS; compliance rules run regardless. |
166
174
 
167
175
  Each platform has 52–54 rules across 10 compliance domains (feed, comments, moderation, chat, secrets, session & auth, notifications, live objects, logging hygiene, design tokens).
168
176
 
@@ -251,7 +259,7 @@ The flow above is what the skill teaches your AI agent. You — the human — dr
251
259
  | `vise design check [path]` | Advisory, **non-blocking** report on how closely the UI code matches the contract (token coverage + on/off-contract color literals). Never fails a build and is **not** a `vise check` gate |
252
260
  | `vise design preview [path] [--reference <prototype>]` | Write a self-contained `sp-vise/design-preview.html`: the contract's tokens as visual swatches + the conformance report + the HTML reference embedded for side-by-side review. Vise renders the artifact; a human/VLM judges the visual match. Dependency-free — **not** an automated pixel diff |
253
261
  | `vise design reference [path] [--title <name>]` | Write a self-contained `sp-vise/design-reference.html`: human/VLM-readable design-system spec — token swatches, type samples, component demos, and a growth-layer summary. Pairs with `design-contract.json` (machine-readable). Use `--title` to name the design system (e.g. `--title Streamly`). Advisory — **not** an enforcement gate |
254
- | `vise design init-tokens [path] [--force]` | Scaffold `src/styles/social-plus-tokens.css` — the dedicated, customer-editable token file for social.plus features. **Greenfield:** neutral defaults (full `--sp-*` token set). **Brownfield:** seeded from your existing concrete tokens. Idempotent — never overwrites an existing file (use `--force` to override). After editing, run `vise design extract --from-project` to refresh the contract. `design_init_tokens` |
262
+ | `vise design init-tokens [path] [--force]` | Scaffold `src/styles/social-plus-tokens.css` — the dedicated, customer-editable token file for social.plus features. **Greenfield:** neutral defaults (full `--sp-*` token set). **Brownfield:** seeded from your existing concrete tokens. Idempotent — never overwrites an existing file (use `--force` to override). After editing, run `vise design extract --from-project` to refresh the contract |
255
263
 
256
264
  The extracted contract is **advisory input for generation**, not an enforcement gate: a token-poor prototype yields a weaker — never wrong — contract, and absence of a prototype simply means no contract (the existing `*.design.reuse-detected-tokens` rules still cover reuse of a host project's own design system).
257
265
 
@@ -279,7 +287,7 @@ The extracted contract is **advisory input for generation**, not an enforcement
279
287
 
280
288
  | Command | Purpose |
281
289
  |---|---|
282
- | `vise run-sensors [path]` | Run detected project commands (npm scripts, Gradle, Flutter, lint, typecheck, SDK import smokes); never executes arbitrary shell |
290
+ | `vise run-sensors [path]` | Run detected project scripts/wrappers (npm scripts, Gradle, Flutter, lint, typecheck, SDK import smokes); inspect with `--dry-run` before running in an untrusted project |
283
291
  | `vise run-sensors [path] --dry-run` | List what would run without executing |
284
292
 
285
293
  ### Troubleshooting quick loop
@@ -335,7 +343,7 @@ MCP-capable hosts can call Vise as structured tool calls instead of shell comman
335
343
 
336
344
  ### Tool names (snake_case per MCP convention)
337
345
 
338
- `inspect_project`, `plan_harness`, `plan_integration`, `init_compliance`, `check_compliance`, `sync_compliance`, `attest_rule`, `explain_rule`, `init_engagement`, `show_engagement`, `search_docs`, `get_doc_page`, `debug_issue`, `validate_setup`, `run_sensors`.
346
+ `inspect_project`, `plan_harness`, `plan_integration`, `init_compliance`, `check_compliance`, `sync_compliance`, `attest_rule`, `explain_rule`, `init_engagement`, `show_engagement`, `resolve_request`, `search_docs`, `get_doc_page`, `debug_issue`, `validate_setup`, `run_sensors`, `suggest_patch`, `design_extract`, `design_check`, `design_preview`, `design_reference`, `design_init_tokens`.
339
347
 
340
348
  These are the same operations as the CLI commands above, exposed as MCP tools.
341
349
 
@@ -388,6 +396,8 @@ After `vise init`, your project gets a `sp-vise/` directory. These files become
388
396
  | `sp-vise/compliance.json` | `vise init` | The rules selected for this integration, the Vise version, the ruleset digest, the target app surface, and an optional engagement link. |
389
397
  | `sp-vise/attestations/*.json` | `vise sync` (deterministic) or `vise attest` (host-agent / human) | Per-rule evidence: signer, confidence, rationale, cited files (with source fingerprints for drift detection). |
390
398
  | `sp-vise/inspection.json` | `vise init` | The platform, monorepo surface, and design-token signals detected at init time. |
399
+ | `sp-vise/design-contract.json` | `vise design extract` | The extracted design contract: declared tokens, breakpoints, advisory components, source file digests (for freshness detection), and a stable digest over design facts. |
400
+ | `sp-vise/design-reference.html` | `vise design reference` | Self-contained HTML design-system spec (token swatches, type samples, components). Human/VLM-readable; open in a browser alongside the app. |
391
401
  | `sp-vise/engagement.json` | `vise engagement init` (optional) | Contractual scope: tier, customer ID, contracted outcomes, reviewer assignment. |
392
402
 
393
403
  **Commit `sp-vise/` to your repo.** `vise check` re-validates against the recorded contract on every run, comparing current code against the recorded attestations. If code changes and breaks a rule, the next `check` reports `deterministic-fail`, `attestation-needed`, or `blocked` — never a silent regression.
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { copyFile, mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
2
+ import { copyFile, mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -41,6 +41,10 @@ const tools = new Map([
41
41
  designInitTokensTool,
42
42
  ].map((tool) => [tool.name, tool]));
43
43
  const bundledSkillName = "social-plus-vise";
44
+ // Pre-rebrand `install-skill` runs created skill dirs/files under this name. We
45
+ // supersede (remove) them on install so a host doesn't keep serving stale
46
+ // foundry/spf guidance alongside the current skill.
47
+ const legacySkillName = "social-plus-foundry";
44
48
  const cliResult = await handleCli(process.argv.slice(2));
45
49
  if (cliResult === "exit") {
46
50
  process.exitCode = process.exitCode ?? 0;
@@ -608,6 +612,7 @@ async function installSkill(args) {
608
612
  }
609
613
  const destination = skillInstallDestination(args);
610
614
  const force = hasFlag(args, "force");
615
+ const supersededLegacy = await removeLegacySkillDir(destination);
611
616
  const installedFiles = await copyDirectory(source, destination, force);
612
617
  return {
613
618
  status: installedFiles.length > 0 ? "installed" : "already-current",
@@ -616,13 +621,36 @@ async function installSkill(args) {
616
621
  destination,
617
622
  force,
618
623
  installedFiles,
624
+ supersededLegacy,
619
625
  nextStep: "Restart or reload the host AI coding tool so it discovers the installed skill.",
620
626
  };
621
627
  }
628
+ // Supersede a pre-rebrand skill install: a prior `install-skill` under the old
629
+ // package name created a sibling `<skillsRoot>/social-plus-foundry/` directory. Left
630
+ // in place, the host keeps offering stale spf/foundry guidance next to the current
631
+ // skill. Remove it on install — but only when it actually looks like a skill dir
632
+ // (contains SKILL.md) and is not the directory we're installing into.
633
+ async function removeLegacySkillDir(destination) {
634
+ const legacyDir = path.join(path.dirname(destination), legacySkillName);
635
+ if (legacyDir === destination) {
636
+ return [];
637
+ }
638
+ if (!(await fileExists(path.join(legacyDir, "SKILL.md")))) {
639
+ return [];
640
+ }
641
+ await rm(legacyDir, { recursive: true, force: true });
642
+ return [legacyDir];
643
+ }
622
644
  async function installInstructionFile(target, args) {
623
645
  const force = hasFlag(args, "force");
624
646
  const source = path.join(skillSourceDir(), "SKILL.md");
625
647
  const content = await readFile(source, "utf8");
648
+ const legacyRule = path.join(path.dirname(target.destination), `${legacySkillName}.mdc`);
649
+ const supersededLegacy = [];
650
+ if (legacyRule !== target.destination && (await fileExists(legacyRule))) {
651
+ await rm(legacyRule, { force: true });
652
+ supersededLegacy.push(legacyRule);
653
+ }
626
654
  if (await fileExists(target.destination)) {
627
655
  const existing = await readFile(target.destination, "utf8");
628
656
  if (existing === content) {
@@ -634,6 +662,7 @@ async function installInstructionFile(target, args) {
634
662
  destination: target.destination,
635
663
  force,
636
664
  installedFiles: [],
665
+ supersededLegacy,
637
666
  nextStep: "Restart or reload the host AI coding tool so it discovers the updated project instructions.",
638
667
  };
639
668
  }
@@ -651,6 +680,7 @@ async function installInstructionFile(target, args) {
651
680
  destination: target.destination,
652
681
  force,
653
682
  installedFiles: [target.destination],
683
+ supersededLegacy,
654
684
  nextStep: "Restart or reload the host AI coding tool so it discovers the updated project instructions.",
655
685
  };
656
686
  }
@@ -891,7 +921,24 @@ function optionalNumberFlag(args, name) {
891
921
  return number;
892
922
  }
893
923
  function hasFlag(args, name) {
894
- return args.includes(`--${name}`);
924
+ const exact = `--${name}`;
925
+ const equalsPrefix = `${exact}=`;
926
+ for (const arg of args) {
927
+ if (arg === exact) {
928
+ return true;
929
+ }
930
+ if (arg.startsWith(equalsPrefix)) {
931
+ const raw = arg.slice(equalsPrefix.length).trim().toLowerCase();
932
+ if (raw === "" || raw === "true" || raw === "1" || raw === "yes") {
933
+ return true;
934
+ }
935
+ if (raw === "false" || raw === "0" || raw === "no") {
936
+ return false;
937
+ }
938
+ throw new Error(`--${name} must be a boolean when provided with "=".`);
939
+ }
940
+ }
941
+ return false;
895
942
  }
896
943
  function keyValueFlag(args, name) {
897
944
  const pairs = flagValues(args, name);
package/dist/tools/ast.js CHANGED
@@ -10,10 +10,46 @@
10
10
  * Scope: Single-file, single-step identifier resolution only.
11
11
  * No cross-file imports, no type inference, no function boundary traversal.
12
12
  */
13
- import Parser from "tree-sitter";
14
- import TypeScriptGrammars from "tree-sitter-typescript";
15
- import KotlinGrammar from "tree-sitter-kotlin";
16
- const { typescript: tsGrammar, tsx: tsxGrammar } = TypeScriptGrammars;
13
+ import { createRequire } from "node:module";
14
+ const nodeRequire = createRequire(import.meta.url);
15
+ // Lazily and defensively load the tree-sitter native bindings. tree-sitter ships
16
+ // prebuilt binaries for common platforms (darwin, linux-x64, win32-x64); on others
17
+ // (linux-arm64, Alpine/musl, win32-arm64) the binding can fail to load when no C++
18
+ // toolchain is present. AST is an ADDITIVE layer over the regex validators, so a
19
+ // load failure must degrade to regex-only — NOT take down the entire CLI (including
20
+ // doc-search/compliance commands that never touch a parser) at import time. Static
21
+ // top-level imports would throw at module load and brick every command; this loader
22
+ // confines the failure to the AST path. `undefined` = not yet attempted; `null` =
23
+ // attempted and unavailable.
24
+ let nativeBindings;
25
+ function loadNativeBindings() {
26
+ if (nativeBindings !== undefined)
27
+ return nativeBindings;
28
+ try {
29
+ const ParserCtor = nodeRequire("tree-sitter");
30
+ const tsGrammars = nodeRequire("tree-sitter-typescript");
31
+ const kotlinGrammar = nodeRequire("tree-sitter-kotlin");
32
+ nativeBindings = {
33
+ Parser: ParserCtor,
34
+ tsGrammar: tsGrammars.typescript,
35
+ tsxGrammar: tsGrammars.tsx,
36
+ kotlinGrammar,
37
+ };
38
+ }
39
+ catch {
40
+ nativeBindings = null;
41
+ }
42
+ return nativeBindings;
43
+ }
44
+ /**
45
+ * Whether tree-sitter native bindings are available in this environment. When
46
+ * false, every AST helper degrades gracefully: parse() throws (so tryParse()
47
+ * returns null and stripComments() returns the source unchanged), and validators
48
+ * fall back to their regex paths.
49
+ */
50
+ export function astAvailable() {
51
+ return loadNativeBindings() !== null;
52
+ }
17
53
  /**
18
54
  * Strip comments from source code using tree-sitter AST.
19
55
  * Replaces comment spans with whitespace (preserving line structure).
@@ -56,13 +92,17 @@ const parsers = new Map();
56
92
  function getParser(language) {
57
93
  let parser = parsers.get(language);
58
94
  if (!parser) {
59
- parser = new Parser();
95
+ const native = loadNativeBindings();
96
+ if (!native) {
97
+ throw new Error("tree-sitter native bindings unavailable; AST analysis disabled (regex fallback in effect)");
98
+ }
99
+ parser = new native.Parser();
60
100
  if (language === "tsx")
61
- parser.setLanguage(tsxGrammar);
101
+ parser.setLanguage(native.tsxGrammar);
62
102
  else if (language === "kotlin")
63
- parser.setLanguage(KotlinGrammar);
103
+ parser.setLanguage(native.kotlinGrammar);
64
104
  else
65
- parser.setLanguage(tsGrammar);
105
+ parser.setLanguage(native.tsGrammar);
66
106
  parsers.set(language, parser);
67
107
  }
68
108
  return parser;
@@ -188,6 +188,7 @@ export async function initEngagement(args) {
188
188
  : undefined;
189
189
  const engagement = {
190
190
  schema_version: schemaVersion,
191
+ vise_version: packageVersion,
191
192
  foundry_version: packageVersion,
192
193
  engagement_id: randomUUID(),
193
194
  customer_id: args.customerId,
@@ -235,6 +236,7 @@ export async function initCompliance(repoPath, request, surfacePath) {
235
236
  const designContract = await readDesignContract(repoRoot);
236
237
  const compliance = {
237
238
  schema_version: schemaVersion,
239
+ vise_version: packageVersion,
238
240
  foundry_version: packageVersion,
239
241
  ruleset_digest: digestJson(refs), // hash of minimal refs (no title)
240
242
  generated_at: new Date().toISOString(),
@@ -688,6 +690,7 @@ function buildAttestation(compliance, rule, signer, confidence, identity, ration
688
690
  rule_version: rule.version,
689
691
  rule_digest: ref.rule_digest,
690
692
  ruleset_digest: compliance.ruleset_digest,
693
+ vise_version: packageVersion,
691
694
  foundry_version: packageVersion,
692
695
  status: signer === "spf-deterministic" ? "deterministic-pass" : "attested",
693
696
  signer_claim: {
@@ -974,7 +977,7 @@ function sidecarReadme(compliance) {
974
977
  "## Quick start",
975
978
  "",
976
979
  "1. Read `findings.json` — it contains a snapshot of rule status taken at init time, including any violations found in the current code.",
977
- "2. Fix the issues listed in `findings.json`, then run `npm run sp-check` (or `vise check .` if vise is on PATH) to verify.",
980
+ "2. Fix the issues listed in `findings.json`, then run `vise check .` to verify.",
978
981
  "3. Run `vise sync .` to persist deterministic-pass evidence once rules are green.",
979
982
  "4. Run `vise attest . --rule <rule-id> ...` to sign off on intentional implementation decisions.",
980
983
  "",
@@ -1570,6 +1570,7 @@ export function buildDesignContract(sources, sourceMeta, extraDeclaredTokens = [
1570
1570
  const inferredCount = tokens.filter((token) => token.provenance === "inferred").length;
1571
1571
  const contract = {
1572
1572
  schema_version: DESIGN_CONTRACT_SCHEMA_VERSION,
1573
+ vise_version: packageVersion,
1573
1574
  foundry_version: packageVersion,
1574
1575
  source: sourceMeta,
1575
1576
  digest: "",
@@ -210,7 +210,7 @@ function assessHarnessability(platforms, commandSensors, designSignalCount) {
210
210
  else {
211
211
  gaps.push("No platform signals detected; ask the user for the app framework or repository root.");
212
212
  }
213
- if (platforms.some((platform) => ["typescript", "react-native", "android", "flutter"].includes(platform))) {
213
+ if (platforms.some((platform) => ["typescript", "react-native", "android", "flutter", "ios"].includes(platform))) {
214
214
  affordances.push("Detected a platform with deterministic setup checks available in Vise.");
215
215
  }
216
216
  if (commandSensors.length > 0) {
@@ -223,7 +223,7 @@ function assessHarnessability(platforms, commandSensors, designSignalCount) {
223
223
  affordances.push(`Detected ${designSignalCount} design/theme signal(s) for UI integration grounding.`);
224
224
  }
225
225
  if (platforms.includes("ios")) {
226
- gaps.push("iOS support is guided until deterministic validators are expanded.");
226
+ gaps.push("iOS: static compliance rules are fully operational. No build/compile sensor is wired yet (xcodebuild environment requirements make it fragile); run-sensors will return no-sensors for iOS projects.");
227
227
  }
228
228
  if (platforms.length === 0) {
229
229
  return { level: "weak", affordances, gaps };
@@ -74,7 +74,7 @@ async function inspectRoot(root) {
74
74
  }
75
75
  // When react-native is detected alongside generic typescript signals, prefer react-native
76
76
  // so that platform-specific rules (react-native.*) are used for init/check/run-sensors.
77
- // Same for android: an agent may create package.json (e.g. to enable npm run sp-check) which
77
+ // Same for android: an agent may create package.json (e.g. to enable a local Vise check script) which
78
78
  // would normally trigger typescript detection — suppress it so only android rules apply.
79
79
  const rawPlatforms = Array.from(new Set(signals.map((signal) => signal.platform)));
80
80
  const hasRN = rawPlatforms.includes("react-native");
@@ -1118,9 +1118,11 @@ function validateChat(root, platform, sourceContent) {
1118
1118
  }
1119
1119
  }
1120
1120
  }
1121
- // channel-target-resolved: check for hardcoded channelId/conversationId
1121
+ // channel-target-resolved: check for hardcoded channelId/conversationId.
1122
+ // Comment-stripped so a commented-out or documented channelId can't trip this
1123
+ // no-escape (exit-2) gate.
1122
1124
  for (const filePath of chatFiles) {
1123
- const content = sourceContent.get(filePath) ?? "";
1125
+ const content = commentStripped(filePath, platform, sourceContent.get(filePath) ?? "");
1124
1126
  const hardcodedChannel = /(?:channelId|conversationId|channel_id)\b[^=\n]*=\s*["'`][a-z0-9-]+["'`]/i.exec(content);
1125
1127
  if (hardcodedChannel) {
1126
1128
  findings.push(finding(`${platform}.chat.channel-target-resolved`, "error", "Chat code references a hardcoded channelId or conversationId.", relativeFile(root, filePath), "Resolve the channel from user selection, SDK query, or app routing — never hardcode."));
@@ -1504,7 +1506,7 @@ function validateLiteralGuardrails(root, platform, sourceContent) {
1504
1506
  /\btargetId\b\s*[:=]\s*["'`]([^"'`]+)["'`]/i,
1505
1507
  /\bfeedId\b\s*[:=]\s*["'`]([^"'`]+)["'`]/i,
1506
1508
  /\bchannelId\b\s*[:=]\s*["'`]([^"'`]+)["'`]/i,
1507
- ]);
1509
+ ], platform);
1508
1510
  if (feedTarget && !isAllowedPlaceholder(feedTarget.value)) {
1509
1511
  findings.push(finding(`${platform}.feed.target.literal`, "warning", `A hardcoded feed target literal was found: ${feedTarget.name}.`, relativeFile(root, feedTarget.file), "Do not invent or hardcode communityId, targetId, feedId, or channelId. Ask the user for the target or use an existing app-owned selection/create flow."));
1510
1512
  }
@@ -1531,7 +1533,7 @@ function validateLiteralGuardrails(root, platform, sourceContent) {
1531
1533
  /\bapi[-_]?key\b\s*[:=][\s\S]{0,200}?(?:process\.env\.[A-Z0-9_]+|import\.meta\.env\.[A-Z0-9_]+)\s*(?:\?\?|\|\|)\s*["'`]([^"'`]+)["'`]/i,
1532
1534
  // Ternary fallback: `apiKey = X ? 'literal' : ...` captures the truthy branch.
1533
1535
  /\bapi[-_]?key\b\s*[:=][\s\S]{0,200}?\?\s*["'`]([^"'`]+)["'`]\s*:/i,
1534
- ]);
1536
+ ], platform);
1535
1537
  if (inlineApiKey && !isAllowedPlaceholder(inlineApiKey.value)) {
1536
1538
  findings.push(finding(`${platform}.secret.inline-api-key`, "warning", "A social.plus API key appears to be hardcoded in source.", relativeFile(root, inlineApiKey.file), "Use the host app's environment/config pattern instead of committing API keys directly into source files. The literal is still committed even when wrapped in an env-fallback (e.g. `defaultValue:`, `??`, `||`, ternary)."));
1537
1539
  }
@@ -1543,7 +1545,7 @@ function validateLiteralGuardrails(root, platform, sourceContent) {
1543
1545
  /\buser_id\s*[:=]\s*["'`]([^"'`]+)["'`]/i,
1544
1546
  /\.login\s*\(\s*["'`]([^"'`]+)["'`]/i,
1545
1547
  /\.login\s*\(\s*userId\s*:\s*["'`]([^"'`]+)["'`]/i,
1546
- ]);
1548
+ ], platform);
1547
1549
  if (literalUserId && !isAllowedPlaceholder(literalUserId.value)) {
1548
1550
  findings.push(finding(`${platform}.auth.no-literal-user-id`, "warning", `A hardcoded user identity literal was found: ${literalUserId.name}.`, relativeFile(root, literalUserId.file), "Do not hardcode a userId in source. Read the authenticated user from the host app's auth state (current session, route param, user-store hook, etc.)."));
1549
1551
  }
@@ -1682,8 +1684,9 @@ function validateLiteralGuardrails(root, platform, sourceContent) {
1682
1684
  }
1683
1685
  return findings;
1684
1686
  }
1685
- function firstLiteralAssignment(contents, patterns) {
1686
- for (const [file, content] of contents) {
1687
+ function firstLiteralAssignment(contents, patterns, platform) {
1688
+ for (const [file, rawContent] of contents) {
1689
+ const content = commentStripped(file, platform, rawContent);
1687
1690
  for (const pattern of patterns) {
1688
1691
  pattern.lastIndex = 0;
1689
1692
  const match = pattern.exec(content);
@@ -2162,6 +2165,87 @@ function astLanguageForFile(filePath, platform) {
2162
2165
  }
2163
2166
  return undefined;
2164
2167
  }
2168
+ // Comment-aware view of a source file for the presence-of-a-bad-literal regex
2169
+ // checks that GATE (channel-target-resolved, inline secrets, literal userId/feed
2170
+ // target). A pattern that appears only in a commented-out or documentation line
2171
+ // must not trip a gate — a hard CI failure on a comment is the worst false positive
2172
+ // a compliance gate can produce. ts/tsx/kotlin use the precise tree-sitter stripper;
2173
+ // Swift/Dart (no grammar wired) use the conservative scanner below. Anything else is
2174
+ // returned unchanged.
2175
+ function commentStripped(filePath, platform, content) {
2176
+ const astLang = astLanguageForFile(filePath, platform);
2177
+ if (astLang)
2178
+ return stripComments(astLang, content);
2179
+ const ext = path.extname(filePath).toLowerCase();
2180
+ if (ext === ".swift" || ext === ".dart")
2181
+ return stripLineAndBlockComments(content);
2182
+ return content;
2183
+ }
2184
+ // Conservative comment stripper for languages without a wired tree-sitter grammar
2185
+ // (Swift, Dart). Blanks `//` line comments and `/* */` block comments with spaces,
2186
+ // preserving newlines so offsets/line numbers are unchanged. It tracks single-line
2187
+ // string state ("…" and '…') with escape handling so a `//` inside a string or a URL
2188
+ // ("https://…") is not mistaken for a comment. Critically, it only ever blanks
2189
+ // comment spans — never code or string text — so any mis-classification degrades
2190
+ // toward a residual false-positive (a comment left un-stripped), never a silent
2191
+ // false-negative on a gate. Multi-line/raw strings are not modeled precisely, but the
2192
+ // same fail-toward-firing property holds (worst case: a comment is not stripped).
2193
+ function stripLineAndBlockComments(source) {
2194
+ const out = source.split("");
2195
+ let inString = null;
2196
+ let inBlock = false;
2197
+ let i = 0;
2198
+ while (i < source.length) {
2199
+ const c = source[i];
2200
+ const next = source[i + 1];
2201
+ if (inBlock) {
2202
+ if (c === "*" && next === "/") {
2203
+ out[i] = " ";
2204
+ out[i + 1] = " ";
2205
+ i += 2;
2206
+ inBlock = false;
2207
+ continue;
2208
+ }
2209
+ if (c !== "\n")
2210
+ out[i] = " ";
2211
+ i += 1;
2212
+ continue;
2213
+ }
2214
+ if (inString) {
2215
+ // Escape: skip the next char — but never jump past a newline, so a stray
2216
+ // trailing backslash can't swallow the following line of real code.
2217
+ if (c === "\\" && next !== "\n") {
2218
+ i += 2;
2219
+ continue;
2220
+ }
2221
+ if (c === inString || c === "\n")
2222
+ inString = null;
2223
+ i += 1;
2224
+ continue;
2225
+ }
2226
+ if (c === '"' || c === "'") {
2227
+ inString = c;
2228
+ i += 1;
2229
+ continue;
2230
+ }
2231
+ if (c === "/" && next === "/") {
2232
+ for (let j = i; j < source.length && source[j] !== "\n"; j += 1)
2233
+ out[j] = " ";
2234
+ while (i < source.length && source[i] !== "\n")
2235
+ i += 1;
2236
+ continue;
2237
+ }
2238
+ if (c === "/" && next === "*") {
2239
+ out[i] = " ";
2240
+ out[i + 1] = " ";
2241
+ i += 2;
2242
+ inBlock = true;
2243
+ continue;
2244
+ }
2245
+ i += 1;
2246
+ }
2247
+ return out.join("");
2248
+ }
2165
2249
  function validateCommentReferenceTypeEnum(root, platform, sourceContent) {
2166
2250
  const findings = [];
2167
2251
  // TypeScript/React Native: the SDK types referenceType as the string-literal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/social-plus-vise",
3
- "version": "0.12.5",
3
+ "version": "0.13.0",
4
4
  "description": "Skill-guided deterministic CLI for social.plus SDK integration assistance.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",