@amityco/social-plus-vise 0.14.25 → 0.14.26
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 +9 -0
- package/README.md +7 -4
- package/dist/server.js +19 -4
- package/dist/tools/compliance.js +42 -0
- package/dist/tools/creative.js +173 -0
- package/dist/tools/integration.js +122 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ All notable changes to `@amityco/social-plus-vise` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## 0.14.26 — 2026-06-06
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Creative selection bridge:** `vise creative accept --variant <id>` / MCP `creative_accept` now persists `sp-vise/creative-selection.json` from a chosen creative brief candidate.
|
|
11
|
+
- **Plan/init/workplan feed-forward:** matching `vise plan`, `vise init`, and `vise workplan next/status` runs now read accepted creative selections, add a `creativeContext` block, prepend a selected-variant implementation step, mirror the selection into `sp-vise/intake.json`, and derive multi-surface workplan order from selected experience objects.
|
|
12
|
+
|
|
13
|
+
### Verified
|
|
14
|
+
- Expanded `test:creative` to cover creative accept, selection sidecar writes, plan feed-forward, creative-derived workplan ordering, init sidecar mirroring, and MCP `creative_accept` smoke coverage.
|
|
15
|
+
|
|
7
16
|
## 0.14.25 — 2026-06-06
|
|
8
17
|
|
|
9
18
|
### Added
|
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ Correctness is gated by deterministic rules or attestations. Baseline completene
|
|
|
83
83
|
|
|
84
84
|
### Engagement Intelligence roadmap
|
|
85
85
|
|
|
86
|
-
Vise's next architecture track is the social.plus **Engagement Intelligence System**: an outcome-to-experience layer that maps customer goals, archetypes, solution patterns, experience objects, UX patterns, and variants before normal implementation planning. The first advisory runtime slice is `vise creative`: it consumes a request plus optional requirements/prototype inputs, or runs in exploratory mode when requirements are absent,
|
|
86
|
+
Vise's next architecture track is the social.plus **Engagement Intelligence System**: an outcome-to-experience layer that maps customer goals, archetypes, solution patterns, experience objects, UX patterns, and variants before normal implementation planning. The first advisory runtime slice is `vise creative`: it consumes a request plus optional requirements/prototype inputs, or runs in exploratory mode when requirements are absent, writes a local creative brief for user variant selection, and records the accepted variant so `vise plan`, `vise init`, and `vise workplan` can carry that product/UX direction forward. See [docs/ENGAGEMENT_INTELLIGENCE_SYSTEM.md](docs/ENGAGEMENT_INTELLIGENCE_SYSTEM.md), [docs/MONOREPO_ARCHITECTURE.md](docs/MONOREPO_ARCHITECTURE.md), and [packages/intelligence](packages/intelligence).
|
|
87
87
|
|
|
88
88
|
### Relationship to social.plus Block Factory
|
|
89
89
|
|
|
@@ -165,11 +165,12 @@ Aggregate: **98/99 expected feed capabilities** and **27/27 selected optional ca
|
|
|
165
165
|
|
|
166
166
|
### Current Release Validation
|
|
167
167
|
|
|
168
|
-
Version 0.14.
|
|
168
|
+
Version 0.14.26 carries current release proof around the full feed-forward, product-expectation, creative pre-planning, and validation flow:
|
|
169
169
|
|
|
170
170
|
| Surface | What was validated |
|
|
171
171
|
|---|---|
|
|
172
172
|
| **Creative pre-planning** | `vise creative` produces requirements-driven or exploratory Engagement Intelligence briefs, writes `sp-vise/creative-brief.json` / `.md`, asks for `preferred_solution`, and survives packed-package installation with the intelligence catalog bundled. |
|
|
173
|
+
| **Creative selection bridge** | `vise creative accept --variant <id>` writes `sp-vise/creative-selection.json`; matching `vise plan`, `vise init`, and `vise workplan next` runs surface the accepted variant, derive workplan surfaces from its experience objects, and mirror the selection into `sp-vise/intake.json`. |
|
|
173
174
|
| **Product flow** | Local end-to-end smoke covers design extraction, plan feed-forward, blocking intake, answered init, capability check, design conformance, and sensor discovery. |
|
|
174
175
|
| **Multi-surface planning** | Broad social requests are decomposed into a `socialWorkplan` sequence for feed, comments, chat, and profile work instead of forcing a single top-level surface choice. `vise workplan next` tells the host agent which surface to implement next, and `vise workplan complete` records green-check progress in `sp-vise/workplan.json` with per-surface snapshots under `sp-vise/workplan-snapshots/<surface>/`. |
|
|
175
176
|
| **Plan questions** | Plans surface blocking questions such as `design_contract_confirmation`, product-scope questions such as `feed_post_type_scope`, `feed_composer_type_scope`, `comment_tray_scope`, `chat_inbox_scope`, and `profile_identity_scope`, plus optional choices such as `feed_optional_capabilities`. Focused plans still accept `feature_surface` answers when the agent is ready to implement one surface. |
|
|
@@ -304,6 +305,7 @@ The flow above is what the skill teaches your AI agent. You — the human — dr
|
|
|
304
305
|
| `vise doctor` | Verify install; print version, install path, docs source |
|
|
305
306
|
| `vise inspect [path]` | Detect platform, monorepo surfaces, design signals, available sensors |
|
|
306
307
|
| `vise creative [path] --request "..." [--requirements <path\|none>] [--prototype <html>]` | Produce an advisory Engagement Intelligence brief with 2-3 solution variants before normal implementation planning; writes `sp-vise/creative-brief.json` and `.md` unless `--no-write` is set |
|
|
308
|
+
| `vise creative accept [path] --variant <id>` | Accept a creative variant and write `sp-vise/creative-selection.json` so subsequent `plan`, `init`, and `workplan` runs include the selected product/UX direction |
|
|
307
309
|
| `vise plan [path] --request "..."` | Produce a grounded implementation plan with intake questions and docs citations |
|
|
308
310
|
| `vise plan-harness [path] --request "..."` | (Pre-planning step) Build the harness around the request |
|
|
309
311
|
| `vise workplan next [path] --request "..."` | For broad social requests, print the next uncompleted surface plus focused `plan` / `init` / verification commands |
|
|
@@ -408,7 +410,7 @@ MCP-capable hosts can call Vise as structured tool calls instead of shell comman
|
|
|
408
410
|
|
|
409
411
|
### Tool names (snake_case per MCP convention)
|
|
410
412
|
|
|
411
|
-
`inspect_project`, `creative_brief`, `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`.
|
|
413
|
+
`inspect_project`, `creative_brief`, `creative_accept`, `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`.
|
|
412
414
|
|
|
413
415
|
These are the same operations as the CLI commands above, exposed as MCP tools.
|
|
414
416
|
|
|
@@ -461,9 +463,10 @@ Vise writes local planning, compliance, design, and evidence artifacts under `sp
|
|
|
461
463
|
| File | Created by | What it contains |
|
|
462
464
|
|---|---|---|
|
|
463
465
|
| `sp-vise/compliance.json` | `vise init` | The rules selected for this integration, the Vise version, the ruleset digest, the target app surface, selected optional capabilities, optional engagement link, and an accepted design-contract digest when confirmed. |
|
|
464
|
-
| `sp-vise/intake.json` | `vise init` | The request, outcome, intake answers, remaining blocking count, design-review status (`absent`, `needs-confirmation`, `accepted`, or `rejected`), and any retrospective `--allow-unresolved-intake` acknowledgement. |
|
|
466
|
+
| `sp-vise/intake.json` | `vise init` | The request, outcome, intake answers, remaining blocking count, optional creative-selection mirror, design-review status (`absent`, `needs-confirmation`, `accepted`, or `rejected`), and any retrospective `--allow-unresolved-intake` acknowledgement. |
|
|
465
467
|
| `sp-vise/creative-brief.json` | `vise creative` | Advisory Engagement Intelligence brief: mode, objective, inferred goals/archetypes, candidate solution variants, feasibility summary, preferred-solution question, and next plan/workplan commands. |
|
|
466
468
|
| `sp-vise/creative-brief.md` | `vise creative` | Human-readable version of the creative brief for review with the user before selecting a variant. |
|
|
469
|
+
| `sp-vise/creative-selection.json` | `vise creative accept` | Accepted creative variant: source brief, selected goals/archetypes/patterns/objects/UX patterns, surface hints, feasibility notes, and plan/workplan feed-forward context. |
|
|
467
470
|
| `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). |
|
|
468
471
|
| `sp-vise/inspection.json` | `vise init` | The platform, monorepo surface, and design-token signals detected at init time. |
|
|
469
472
|
| `sp-vise/workplan.json` | `vise workplan complete` | Local progress for broad social workplans: request, completed surface IDs, outcomes, timestamps, green-check evidence, snapshot paths, and optional host-agent notes. |
|
package/dist/server.js
CHANGED
|
@@ -17,13 +17,14 @@ import { runSensorsTool } from "./tools/sensors.js";
|
|
|
17
17
|
import { getSdkFactsTool } from "./tools/sdkFacts.js";
|
|
18
18
|
import { addBlockInstall, listRegistryBlocks, planBlockInstall, validateBlockInstall } from "./tools/blocks.js";
|
|
19
19
|
import { debugIssueTool, debugIssue } from "./tools/debug.js";
|
|
20
|
-
import { creativeBriefTool } from "./tools/creative.js";
|
|
20
|
+
import { creativeAcceptTool, creativeBriefTool } from "./tools/creative.js";
|
|
21
21
|
import { packageName, packageVersion } from "./version.js";
|
|
22
22
|
const tools = new Map([
|
|
23
23
|
searchDocsTool,
|
|
24
24
|
getDocPageTool,
|
|
25
25
|
inspectProjectTool,
|
|
26
26
|
creativeBriefTool,
|
|
27
|
+
creativeAcceptTool,
|
|
27
28
|
planHarnessTool,
|
|
28
29
|
planIntegrationTool,
|
|
29
30
|
initComplianceTool,
|
|
@@ -137,6 +138,16 @@ async function handleCli(args) {
|
|
|
137
138
|
return "exit";
|
|
138
139
|
}
|
|
139
140
|
if (command === "creative") {
|
|
141
|
+
if (args[1] === "accept") {
|
|
142
|
+
const subArgs = args.slice(2);
|
|
143
|
+
assertOnlyKnownFlags(subArgs, ["variant", "brief", "brief-path"], "creative accept");
|
|
144
|
+
await printToolResult(creativeAcceptTool, {
|
|
145
|
+
repoPath: positionalRepoPath(subArgs),
|
|
146
|
+
variantId: requiredFlagValue(subArgs, "variant", "creative accept requires --variant <id>."),
|
|
147
|
+
briefPath: flagValue(subArgs, "brief") ?? flagValue(subArgs, "brief-path"),
|
|
148
|
+
});
|
|
149
|
+
return "exit";
|
|
150
|
+
}
|
|
140
151
|
assertOnlyKnownFlags(args, ["request", "requirements", "prototype", "surface", "surface-path", "no-requirements", "no-write"], "creative");
|
|
141
152
|
if (hasFlag(args, "no-requirements") && flagValue(args, "requirements")) {
|
|
142
153
|
throw new Error("creative accepts either --requirements <path> or --no-requirements, not both.");
|
|
@@ -480,10 +491,12 @@ Usage:
|
|
|
480
491
|
vise creative [repoPath] --request "Add engagement" --no-requirements
|
|
481
492
|
vise creative [repoPath] --request "Add engagement" --prototype ./prototype.html
|
|
482
493
|
vise creative [repoPath] --request "Add engagement" --no-write
|
|
494
|
+
vise creative accept [repoPath] --variant community-first
|
|
483
495
|
|
|
484
496
|
Output:
|
|
485
497
|
Writes sp-vise/creative-brief.json and sp-vise/creative-brief.md unless --no-write is set.
|
|
486
|
-
Requirements are optional; absence or explicit none switches creative mode to exploratory
|
|
498
|
+
Requirements are optional; absence or explicit none switches creative mode to exploratory.
|
|
499
|
+
creative accept writes sp-vise/creative-selection.json for plan/init/workplan feed-forward.`;
|
|
487
500
|
}
|
|
488
501
|
if (command === "plan-harness") {
|
|
489
502
|
return `${packageName} plan-harness
|
|
@@ -732,6 +745,7 @@ Usage:
|
|
|
732
745
|
vise print-skill Print bundled skill markdown
|
|
733
746
|
vise inspect [repoPath] Inspect platform and design signals
|
|
734
747
|
vise creative [repoPath] --request "..." Create an Engagement Intelligence brief
|
|
748
|
+
vise creative accept [repoPath] --variant <id> Accept a creative variant
|
|
735
749
|
vise debug [repoPath] --error ... Debug an SDK-specific runtime error and emit a repair brief
|
|
736
750
|
vise plan [repoPath] --request "..." Create an implementation plan
|
|
737
751
|
vise workplan next [repoPath] --request "..." Get the next broad-social surface to implement
|
|
@@ -1006,6 +1020,7 @@ async function workplanStatus(args) {
|
|
|
1006
1020
|
status: nextSurface ? "next-surface" : "complete",
|
|
1007
1021
|
request,
|
|
1008
1022
|
progressPath: workplanProgressPath(repoRoot),
|
|
1023
|
+
creativeContext: plan.socialWorkplan?.creativeContext ?? plan.creativeContext,
|
|
1009
1024
|
completed,
|
|
1010
1025
|
sequence: sequence.map((surface) => ({
|
|
1011
1026
|
id: surface.id,
|
|
@@ -1207,7 +1222,7 @@ function ciCheckResult(result) {
|
|
|
1207
1222
|
};
|
|
1208
1223
|
}
|
|
1209
1224
|
function positionalRepoPath(args) {
|
|
1210
|
-
const flagsWithValues = new Set(["request", "requirements", "prototype", "surface", "surface-path", "platform", "capability", "surface-dir", "format", "include", "timeout-ms", "query", "path", "limit", "answer", "target", "dest", "destination", "rule", "confidence", "signer", "identity", "evidence-file", "rationale", "repo", "reference", "registry", "block", "package-source", "note"]);
|
|
1225
|
+
const flagsWithValues = new Set(["request", "requirements", "prototype", "variant", "brief", "brief-path", "surface", "surface-path", "platform", "capability", "surface-dir", "format", "include", "timeout-ms", "query", "path", "limit", "answer", "target", "dest", "destination", "rule", "confidence", "signer", "identity", "evidence-file", "rationale", "repo", "reference", "registry", "block", "package-source", "note"]);
|
|
1211
1226
|
for (let index = 0; index < args.length; index += 1) {
|
|
1212
1227
|
const arg = args[index];
|
|
1213
1228
|
if (!arg) {
|
|
@@ -1229,7 +1244,7 @@ function positionalRepoPath(args) {
|
|
|
1229
1244
|
}
|
|
1230
1245
|
function requiredPositionalText(args, message) {
|
|
1231
1246
|
const values = [];
|
|
1232
|
-
const flagsWithValues = new Set(["request", "requirements", "prototype", "surface", "surface-path", "platform", "capability", "surface-dir", "format", "include", "timeout-ms", "query", "path", "limit", "answer", "target", "dest", "destination", "rule", "confidence", "signer", "identity", "evidence-file", "rationale", "repo", "reference", "registry", "block", "package-source", "note"]);
|
|
1247
|
+
const flagsWithValues = new Set(["request", "requirements", "prototype", "variant", "brief", "brief-path", "surface", "surface-path", "platform", "capability", "surface-dir", "format", "include", "timeout-ms", "query", "path", "limit", "answer", "target", "dest", "destination", "rule", "confidence", "signer", "identity", "evidence-file", "rationale", "repo", "reference", "registry", "block", "package-source", "note"]);
|
|
1233
1248
|
for (let index = 0; index < args.length; index += 1) {
|
|
1234
1249
|
const arg = args[index];
|
|
1235
1250
|
if (!arg) {
|
package/dist/tools/compliance.js
CHANGED
|
@@ -9,6 +9,7 @@ import { objectInput, optionalBooleanField, optionalStringField, stringField, te
|
|
|
9
9
|
import { packageVersion } from "../version.js";
|
|
10
10
|
import { DESIGN_CONTRACT_CONFIRMATION_ANSWER_ID, buildDesignBrief, designContractConfirmationFromAnswers, designPreviewPath, readDesignContract, } from "./design.js";
|
|
11
11
|
import { inspectProject, validateSetup } from "./project.js";
|
|
12
|
+
import { readCreativeSelection } from "./creative.js";
|
|
12
13
|
const complianceDirName = "sp-vise";
|
|
13
14
|
const attestationsDirName = "attestations";
|
|
14
15
|
const schemaVersion = 1;
|
|
@@ -298,6 +299,10 @@ export async function initCompliance(repoPath, request, surfacePath, answers = {
|
|
|
298
299
|
const designContract = await readDesignContract(repoRoot);
|
|
299
300
|
const designReview = designReviewFor(repoRoot, designContract, answers);
|
|
300
301
|
const acceptedDesignContract = designReview.status === "accepted" ? designContract : null;
|
|
302
|
+
const storedCreativeSelection = await readCreativeSelection(repoRoot);
|
|
303
|
+
const creativeSelection = storedCreativeSelection && creativeSelectionAppliesToRequest(storedCreativeSelection, request)
|
|
304
|
+
? storedCreativeSelection
|
|
305
|
+
: undefined;
|
|
301
306
|
const intake = intakeAuditFor({
|
|
302
307
|
request,
|
|
303
308
|
outcome,
|
|
@@ -346,6 +351,7 @@ export async function initCompliance(repoPath, request, surfacePath, answers = {
|
|
|
346
351
|
generated_at: compliance.generated_at,
|
|
347
352
|
request,
|
|
348
353
|
outcome,
|
|
354
|
+
...(creativeSelection ? { creative_selection: creativeSelectionSummary(creativeSelection) } : {}),
|
|
349
355
|
design_review: designReview,
|
|
350
356
|
...intake,
|
|
351
357
|
});
|
|
@@ -373,6 +379,7 @@ export async function initCompliance(repoPath, request, surfacePath, answers = {
|
|
|
373
379
|
surfacePath: inspection.selectedSurface?.path,
|
|
374
380
|
rules: refs.length,
|
|
375
381
|
engagement_id: engagement?.engagement_id,
|
|
382
|
+
...(creativeSelection ? { creative_selection: creativeSelectionSummary(creativeSelection) } : {}),
|
|
376
383
|
...(compliance.design_contract && { design_contract: compliance.design_contract }),
|
|
377
384
|
...(selectedOptionalCapabilities.length > 0 && { selected_optional_capabilities: selectedOptionalCapabilities }),
|
|
378
385
|
intake: {
|
|
@@ -469,6 +476,41 @@ function intakeAuditFor(args) {
|
|
|
469
476
|
acknowledged_unresolved_blocking: args.allowUnresolvedIntake && remainingBlocking > 0,
|
|
470
477
|
};
|
|
471
478
|
}
|
|
479
|
+
function creativeSelectionSummary(selection) {
|
|
480
|
+
return {
|
|
481
|
+
status: selection.status,
|
|
482
|
+
selection_path: "sp-vise/creative-selection.json",
|
|
483
|
+
source_brief: selection.source.brief,
|
|
484
|
+
mode: selection.source.mode,
|
|
485
|
+
original_request: selection.source.request,
|
|
486
|
+
plan_request: selection.implementationContext.planRequest,
|
|
487
|
+
selected_variant: {
|
|
488
|
+
id: selection.selectedVariant.id,
|
|
489
|
+
title: selection.selectedVariant.title,
|
|
490
|
+
businessGoalIds: selection.selectedVariant.businessGoalIds,
|
|
491
|
+
archetypeIds: selection.selectedVariant.archetypeIds,
|
|
492
|
+
solutionPatternIds: selection.selectedVariant.solutionPatternIds,
|
|
493
|
+
experienceObjectIds: selection.selectedVariant.experienceObjectIds,
|
|
494
|
+
uxPatternIds: selection.selectedVariant.uxPatternIds,
|
|
495
|
+
feasibilitySupport: selection.selectedVariant.feasibility.support,
|
|
496
|
+
},
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
function creativeSelectionAppliesToRequest(selection, request) {
|
|
500
|
+
const normalizedRequest = normalizeCreativeRequest(request);
|
|
501
|
+
const original = normalizeCreativeRequest(selection.source.request);
|
|
502
|
+
const planRequest = normalizeCreativeRequest(selection.implementationContext.planRequest);
|
|
503
|
+
if (!normalizedRequest || !original) {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
return (normalizedRequest === original ||
|
|
507
|
+
normalizedRequest === planRequest ||
|
|
508
|
+
normalizedRequest.includes(original) ||
|
|
509
|
+
original.includes(normalizedRequest));
|
|
510
|
+
}
|
|
511
|
+
function normalizeCreativeRequest(value) {
|
|
512
|
+
return value.toLowerCase().replace(/[^a-z0-9\s]+/g, " ").replace(/\s+/g, " ").trim();
|
|
513
|
+
}
|
|
472
514
|
function preferredPlatform(platforms) {
|
|
473
515
|
const order = ["flutter", "android", "typescript", "react-native", "ios"];
|
|
474
516
|
return order.find((platform) => platforms.includes(platform)) ?? platforms[0] ?? "unknown";
|
package/dist/tools/creative.js
CHANGED
|
@@ -6,8 +6,10 @@ import { objectInput, optionalBooleanField, optionalStringField, stringField, te
|
|
|
6
6
|
import { packageVersion } from "../version.js";
|
|
7
7
|
import { inspectProject } from "./project.js";
|
|
8
8
|
const CREATIVE_SCHEMA_VERSION = "2026-06-06.vise-creative.v1";
|
|
9
|
+
const CREATIVE_SELECTION_SCHEMA_VERSION = "2026-06-06.vise-creative-selection.v1";
|
|
9
10
|
const BRIEF_JSON = "creative-brief.json";
|
|
10
11
|
const BRIEF_MD = "creative-brief.md";
|
|
12
|
+
const SELECTION_JSON = "creative-selection.json";
|
|
11
13
|
export const creativeBriefTool = {
|
|
12
14
|
name: "creative_brief",
|
|
13
15
|
description: "Create an advisory Engagement Intelligence brief before normal Vise planning. Supports optional requirements and prototype inputs, or exploratory mode when requirements are absent.",
|
|
@@ -54,6 +56,42 @@ export const creativeBriefTool = {
|
|
|
54
56
|
}));
|
|
55
57
|
},
|
|
56
58
|
};
|
|
59
|
+
export const creativeAcceptTool = {
|
|
60
|
+
name: "creative_accept",
|
|
61
|
+
description: "Accept a candidate from sp-vise/creative-brief.json and persist sp-vise/creative-selection.json for plan/init/workplan feed-forward.",
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
repoPath: {
|
|
66
|
+
type: "string",
|
|
67
|
+
description: "Absolute or relative path to the customer repository root.",
|
|
68
|
+
},
|
|
69
|
+
variantId: {
|
|
70
|
+
type: "string",
|
|
71
|
+
description: "Candidate variant id from creative_brief.candidateSolutions.",
|
|
72
|
+
},
|
|
73
|
+
briefPath: {
|
|
74
|
+
type: "string",
|
|
75
|
+
description: "Optional path to a creative brief JSON file. Defaults to sp-vise/creative-brief.json under repoPath.",
|
|
76
|
+
},
|
|
77
|
+
write: {
|
|
78
|
+
type: "boolean",
|
|
79
|
+
description: "Whether to write sp-vise/creative-selection.json. Defaults to true.",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
required: ["repoPath", "variantId"],
|
|
83
|
+
additionalProperties: false,
|
|
84
|
+
},
|
|
85
|
+
async call(input) {
|
|
86
|
+
const args = objectInput(input);
|
|
87
|
+
return textResult(await acceptCreativeVariant({
|
|
88
|
+
repoPath: stringField(args, "repoPath"),
|
|
89
|
+
variantId: stringField(args, "variantId"),
|
|
90
|
+
briefPath: optionalStringField(args, "briefPath"),
|
|
91
|
+
write: optionalBooleanField(args, "write", true),
|
|
92
|
+
}));
|
|
93
|
+
},
|
|
94
|
+
};
|
|
57
95
|
export async function buildCreativeBrief(options) {
|
|
58
96
|
const repoRoot = path.resolve(options.repoPath);
|
|
59
97
|
const request = options.request.trim();
|
|
@@ -108,6 +146,71 @@ export async function buildCreativeBrief(options) {
|
|
|
108
146
|
}
|
|
109
147
|
return brief;
|
|
110
148
|
}
|
|
149
|
+
export async function acceptCreativeVariant(options) {
|
|
150
|
+
const repoRoot = path.resolve(options.repoPath);
|
|
151
|
+
const briefPath = creativeBriefPath(repoRoot, options.briefPath);
|
|
152
|
+
const brief = await readCreativeBrief(repoRoot, options.briefPath);
|
|
153
|
+
const variantId = options.variantId.trim();
|
|
154
|
+
if (!variantId) {
|
|
155
|
+
throw new Error("creative accept requires a non-empty variant id.");
|
|
156
|
+
}
|
|
157
|
+
const selected = brief.candidateSolutions.find((candidate) => candidate.id === variantId);
|
|
158
|
+
if (!selected) {
|
|
159
|
+
throw new Error(`Creative variant "${variantId}" was not found in ${repoRelativePath(repoRoot, briefPath)}. Available variants: ${brief.candidateSolutions.map((candidate) => candidate.id).join(", ") || "(none)"}.`);
|
|
160
|
+
}
|
|
161
|
+
const selection = {
|
|
162
|
+
schema_version: CREATIVE_SELECTION_SCHEMA_VERSION,
|
|
163
|
+
vise_version: packageVersion,
|
|
164
|
+
status: "accepted",
|
|
165
|
+
selected_at: new Date().toISOString(),
|
|
166
|
+
source: {
|
|
167
|
+
brief: repoRelativePath(repoRoot, briefPath),
|
|
168
|
+
brief_schema_version: brief.schema_version,
|
|
169
|
+
brief_generated_at: brief.generated_at,
|
|
170
|
+
mode: brief.mode,
|
|
171
|
+
request: brief.request,
|
|
172
|
+
},
|
|
173
|
+
objective: brief.objective,
|
|
174
|
+
selectedVariant: selected,
|
|
175
|
+
implementationContext: {
|
|
176
|
+
planRequest: `${selected.title}: ${brief.request}`,
|
|
177
|
+
surfaceHints: creativeSurfaceHints(selected),
|
|
178
|
+
designPatternIds: selected.uxPatternIds,
|
|
179
|
+
capabilityNotes: selected.feasibility.notes,
|
|
180
|
+
},
|
|
181
|
+
nextStep: "Run `vise plan . --request <original request>` or `vise workplan next . --request <original request>`; Vise will include this accepted creative selection as advisory implementation context.",
|
|
182
|
+
};
|
|
183
|
+
if (options.write !== false) {
|
|
184
|
+
selection.artifacts = await writeCreativeSelection(repoRoot, selection);
|
|
185
|
+
}
|
|
186
|
+
return selection;
|
|
187
|
+
}
|
|
188
|
+
export async function readCreativeSelection(repoRootOrPath) {
|
|
189
|
+
const repoRoot = path.resolve(repoRootOrPath);
|
|
190
|
+
try {
|
|
191
|
+
return JSON.parse(await readFile(path.join(repoRoot, "sp-vise", SELECTION_JSON), "utf8"));
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
export function creativeSurfaceHints(candidateOrSelection) {
|
|
198
|
+
const candidate = "selectedVariant" in candidateOrSelection ? candidateOrSelection.selectedVariant : candidateOrSelection;
|
|
199
|
+
const hints = [];
|
|
200
|
+
const seen = new Set();
|
|
201
|
+
for (const objectId of candidate.experienceObjectIds) {
|
|
202
|
+
const hint = CREATIVE_SURFACE_HINTS.find((item) => item.objectIds.includes(objectId));
|
|
203
|
+
if (!hint || seen.has(hint.id)) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
seen.add(hint.id);
|
|
207
|
+
hints.push({
|
|
208
|
+
...hint,
|
|
209
|
+
reason: `Selected variant "${candidate.title}" includes experience object "${objectId}".`,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return hints;
|
|
213
|
+
}
|
|
111
214
|
async function loadCatalog() {
|
|
112
215
|
const root = catalogRoot();
|
|
113
216
|
const [businessGoals, archetypes, experienceObjects, solutionPatterns, uxPatterns, variants] = await Promise.all([
|
|
@@ -127,6 +230,32 @@ async function loadCatalog() {
|
|
|
127
230
|
variants: variants.items,
|
|
128
231
|
};
|
|
129
232
|
}
|
|
233
|
+
async function readCreativeBrief(repoRoot, inputPath) {
|
|
234
|
+
const filePath = creativeBriefPath(repoRoot, inputPath);
|
|
235
|
+
try {
|
|
236
|
+
return JSON.parse(await readFile(filePath, "utf8"));
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
240
|
+
throw new Error(`Unable to read creative brief at ${repoRelativePath(repoRoot, filePath)}. Run \`vise creative . --request "..."\` first. ${detail}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function creativeBriefPath(repoRoot, inputPath) {
|
|
244
|
+
if (inputPath) {
|
|
245
|
+
return path.isAbsolute(inputPath) ? inputPath : path.resolve(repoRoot, inputPath);
|
|
246
|
+
}
|
|
247
|
+
return path.join(repoRoot, "sp-vise", BRIEF_JSON);
|
|
248
|
+
}
|
|
249
|
+
async function writeCreativeSelection(repoRoot, selection) {
|
|
250
|
+
const sidecarDir = path.join(repoRoot, "sp-vise");
|
|
251
|
+
await mkdir(sidecarDir, { recursive: true });
|
|
252
|
+
const jsonPath = path.join(sidecarDir, SELECTION_JSON);
|
|
253
|
+
const withoutArtifacts = { ...selection, artifacts: undefined };
|
|
254
|
+
await writeFile(jsonPath, `${JSON.stringify(withoutArtifacts, null, 2)}\n`, "utf8");
|
|
255
|
+
return {
|
|
256
|
+
json: repoRelativePath(repoRoot, jsonPath),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
130
259
|
async function loadCatalogFile(root, fileName) {
|
|
131
260
|
const filePath = path.join(root, fileName);
|
|
132
261
|
try {
|
|
@@ -505,6 +634,50 @@ function repoRelativePath(repoRoot, filePath) {
|
|
|
505
634
|
return path.relative(repoRoot, filePath).split(path.sep).join("/");
|
|
506
635
|
}
|
|
507
636
|
const SOCIAL_PLUS_OBJECTS = new Set(["feed", "comment", "forum", "community", "creator", "profile", "chat", "story", "livestream", "event", "rsvp", "notification"]);
|
|
637
|
+
const CREATIVE_SURFACE_HINTS = [
|
|
638
|
+
{
|
|
639
|
+
id: "feed",
|
|
640
|
+
outcome: "add-feed",
|
|
641
|
+
label: "Feed and content surface",
|
|
642
|
+
objectIds: ["feed", "story", "livestream"],
|
|
643
|
+
reason: "",
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
id: "comments",
|
|
647
|
+
outcome: "add-comments",
|
|
648
|
+
label: "Comments and replies",
|
|
649
|
+
objectIds: ["comment"],
|
|
650
|
+
reason: "",
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
id: "chat",
|
|
654
|
+
outcome: "add-chat",
|
|
655
|
+
label: "Chat inbox and threads",
|
|
656
|
+
objectIds: ["chat"],
|
|
657
|
+
reason: "",
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
id: "profile",
|
|
661
|
+
outcome: "add-follow",
|
|
662
|
+
label: "Profile and relationship graph",
|
|
663
|
+
objectIds: ["profile", "creator"],
|
|
664
|
+
reason: "",
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
id: "community",
|
|
668
|
+
outcome: "add-community",
|
|
669
|
+
label: "Community management and identity",
|
|
670
|
+
objectIds: ["community", "forum"],
|
|
671
|
+
reason: "",
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
id: "notifications",
|
|
675
|
+
outcome: "add-notifications",
|
|
676
|
+
label: "Notifications and activation",
|
|
677
|
+
objectIds: ["notification", "event", "rsvp"],
|
|
678
|
+
reason: "",
|
|
679
|
+
},
|
|
680
|
+
];
|
|
508
681
|
const GOAL_KEYWORDS = {
|
|
509
682
|
retention: ["retention", "retain", "return", "repeat", "habit", "stickiness", "come back", "daily active", "weekly active"],
|
|
510
683
|
participation: ["participation", "participate", "engagement", "social", "comment", "reply", "post", "active", "contribute"],
|
|
@@ -8,6 +8,7 @@ import { DESIGN_CONTRACT_CONFIRMATION_ANSWER_ID, buildDesignBrief, designContrac
|
|
|
8
8
|
import { sdkVersionGuidance } from "./sdkVersion.js";
|
|
9
9
|
import { detectCommandSensors } from "./harness.js";
|
|
10
10
|
import { inspectProject } from "./project.js";
|
|
11
|
+
import { creativeSurfaceHints, readCreativeSelection } from "./creative.js";
|
|
11
12
|
export const planIntegrationTool = {
|
|
12
13
|
name: "plan_integration",
|
|
13
14
|
description: "Create a grounded, evidence-backed implementation packet before an AI coding agent edits a customer project.",
|
|
@@ -58,6 +59,11 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
|
|
|
58
59
|
const repoRoot = path.resolve(repoPath);
|
|
59
60
|
const inspection = await inspectProject(repoRoot, surfacePath);
|
|
60
61
|
const root = inspection.effectiveRoot;
|
|
62
|
+
const storedCreativeSelection = await readCreativeSelection(repoRoot);
|
|
63
|
+
const creativeSelection = storedCreativeSelection && creativeSelectionAppliesToRequest(storedCreativeSelection, request)
|
|
64
|
+
? storedCreativeSelection
|
|
65
|
+
: undefined;
|
|
66
|
+
const creativeContext = creativeSelection ? creativeContextForPlan(creativeSelection) : undefined;
|
|
61
67
|
const outcome = resolveOutcome(request, answers);
|
|
62
68
|
const platform = preferredPlatform(inspection.platforms);
|
|
63
69
|
const supportLevel = supportFor(outcome, platform);
|
|
@@ -89,6 +95,7 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
|
|
|
89
95
|
platform,
|
|
90
96
|
platforms: inspection.platforms,
|
|
91
97
|
designSignals: inspection.designSignals,
|
|
98
|
+
creativeSelection,
|
|
92
99
|
designBrief,
|
|
93
100
|
designReview,
|
|
94
101
|
sensors,
|
|
@@ -109,9 +116,16 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
|
|
|
109
116
|
// reviewable choice rather than a silent drop. Mirrors the detailed `intake`
|
|
110
117
|
// block below; placed here because the intake block lands past common `head`
|
|
111
118
|
// cut points.
|
|
112
|
-
const decisionsRequired =
|
|
113
|
-
|
|
114
|
-
|
|
119
|
+
const decisionsRequired = [
|
|
120
|
+
...(creativeContext
|
|
121
|
+
? [
|
|
122
|
+
`[selected creative variant] Carry "${creativeContext.selectedVariant.title}" into the implementation plan. If any selected experience object is intentionally deferred, state that scope decision explicitly.`,
|
|
123
|
+
]
|
|
124
|
+
: []),
|
|
125
|
+
...intake.questions.map((q) => q.blocksImplementationWhenMissing
|
|
126
|
+
? `[resolve before building] ${q.question}`
|
|
127
|
+
: `[decide & state in your summary] ${q.question}`),
|
|
128
|
+
];
|
|
115
129
|
// Steps-first ordering: implementationSteps + validation lead the object so
|
|
116
130
|
// that an agent piping `vise plan` through `head` still captures the
|
|
117
131
|
// actionable guidance. The verbose scaffolding (intake, docs, surfaces, rule
|
|
@@ -122,16 +136,20 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
|
|
|
122
136
|
platform,
|
|
123
137
|
supportLevel,
|
|
124
138
|
intent: intentFor(request, definition.interpretation),
|
|
139
|
+
creativeContext,
|
|
125
140
|
socialWorkplan,
|
|
126
141
|
capabilityAvailability,
|
|
127
142
|
designReview,
|
|
128
143
|
decisionsRequired,
|
|
129
|
-
implementationSteps: definition.implementationSteps(ctx),
|
|
144
|
+
implementationSteps: [...creativeImplementationSteps(creativeSelection), ...definition.implementationSteps(ctx)],
|
|
130
145
|
validation: ["validate_setup", "run_sensors", ...definition.validation(platform)],
|
|
131
146
|
nextStep: "After implementing every step above, run `vise check .` and fix findings until green. You are not done until the check passes or each finding is explicitly attested.",
|
|
132
147
|
requiredInputs: composeRequiredInputs(ctx, definition.requiredInputs(ctx)),
|
|
133
148
|
targetFiles: await targetFilesFor(root, outcome, platform, inspection.designSignals),
|
|
134
|
-
implementationRules:
|
|
149
|
+
implementationRules: [
|
|
150
|
+
...composeImplementationRules(ctx, definition.implementationRules(ctx)),
|
|
151
|
+
...creativeImplementationRules(creativeSelection),
|
|
152
|
+
],
|
|
135
153
|
intake,
|
|
136
154
|
docs: definition.docs(platform).filter((doc) => doc.path !== "unknown"),
|
|
137
155
|
surface: inspection.selectedSurface ? { path: inspection.selectedSurface.path, platforms: inspection.selectedSurface.platforms } : undefined,
|
|
@@ -177,6 +195,79 @@ function optionalCapabilitiesFor(outcome, answers, request, availability) {
|
|
|
177
195
|
selected: selectedOptionalCapabilityIds(outcome, answers, request, availableIds),
|
|
178
196
|
};
|
|
179
197
|
}
|
|
198
|
+
function creativeContextForPlan(selection) {
|
|
199
|
+
const selectedVariant = selection.selectedVariant;
|
|
200
|
+
const surfaceHints = creativeSurfaceHints(selection);
|
|
201
|
+
const customObjects = selectedVariant.feasibility.customObjectIds;
|
|
202
|
+
return {
|
|
203
|
+
status: "accepted",
|
|
204
|
+
selectionPath: "sp-vise/creative-selection.json",
|
|
205
|
+
sourceBrief: selection.source.brief,
|
|
206
|
+
mode: selection.source.mode,
|
|
207
|
+
originalRequest: selection.source.request,
|
|
208
|
+
selectedVariant: {
|
|
209
|
+
id: selectedVariant.id,
|
|
210
|
+
title: selectedVariant.title,
|
|
211
|
+
confidence: selectedVariant.confidence,
|
|
212
|
+
businessGoalIds: selectedVariant.businessGoalIds,
|
|
213
|
+
archetypeIds: selectedVariant.archetypeIds,
|
|
214
|
+
solutionPatternIds: selectedVariant.solutionPatternIds,
|
|
215
|
+
experienceObjectIds: selectedVariant.experienceObjectIds,
|
|
216
|
+
uxPatternIds: selectedVariant.uxPatternIds,
|
|
217
|
+
feasibilitySupport: selectedVariant.feasibility.support,
|
|
218
|
+
},
|
|
219
|
+
objective: selection.objective,
|
|
220
|
+
surfaceHints,
|
|
221
|
+
implementationGuidance: [
|
|
222
|
+
`Use "${selectedVariant.title}" as the product and UX direction selected by the user before implementation.`,
|
|
223
|
+
`Preserve UX pattern(s): ${selectedVariant.uxPatternIds.join(", ") || "(none)"}.`,
|
|
224
|
+
`Prioritize experience object(s): ${selectedVariant.experienceObjectIds.join(", ") || "(none)"}.`,
|
|
225
|
+
...(customObjects.length > 0
|
|
226
|
+
? [`These experience object(s) are outside current deterministic Vise SDK outcomes and need explicit app-layer scope decisions: ${customObjects.join(", ")}.`]
|
|
227
|
+
: []),
|
|
228
|
+
...(selectedVariant.feasibility.notes.length > 0 ? selectedVariant.feasibility.notes : []),
|
|
229
|
+
],
|
|
230
|
+
nextStep: surfaceHints.length > 1
|
|
231
|
+
? "Use `vise workplan next` to execute the accepted variant one deterministic surface at a time."
|
|
232
|
+
: "Use `vise plan` / `vise init` for the focused surface while preserving the accepted creative direction.",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function creativeImplementationSteps(selection) {
|
|
236
|
+
if (!selection) {
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
const selectedVariant = selection.selectedVariant;
|
|
240
|
+
return [
|
|
241
|
+
{
|
|
242
|
+
step: `Carry the accepted creative variant "${selectedVariant.title}" into this build: solution patterns ${selectedVariant.solutionPatternIds.join(", ")}, UX patterns ${selectedVariant.uxPatternIds.join(", ")}, experience objects ${selectedVariant.experienceObjectIds.join(", ")}.`,
|
|
243
|
+
evidence: ["sp-vise/creative-selection.json", selection.source.brief],
|
|
244
|
+
},
|
|
245
|
+
];
|
|
246
|
+
}
|
|
247
|
+
function creativeImplementationRules(selection) {
|
|
248
|
+
if (!selection) {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
return [
|
|
252
|
+
`Do not silently discard the accepted creative variant "${selection.selectedVariant.title}". If a selected experience object is not implemented in this pass, record it as an explicit scope decision in the handoff.`,
|
|
253
|
+
"Treat creative selection as advisory product/UX feed-forward; deterministic compliance still comes from the focused `vise init` outcome and `vise check` result.",
|
|
254
|
+
];
|
|
255
|
+
}
|
|
256
|
+
function creativeSelectionAppliesToRequest(selection, request) {
|
|
257
|
+
const normalizedRequest = normalizeCreativeRequest(request);
|
|
258
|
+
const original = normalizeCreativeRequest(selection.source.request);
|
|
259
|
+
const planRequest = normalizeCreativeRequest(selection.implementationContext.planRequest);
|
|
260
|
+
if (!normalizedRequest || !original) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
return (normalizedRequest === original ||
|
|
264
|
+
normalizedRequest === planRequest ||
|
|
265
|
+
normalizedRequest.includes(original) ||
|
|
266
|
+
original.includes(normalizedRequest));
|
|
267
|
+
}
|
|
268
|
+
function normalizeCreativeRequest(value) {
|
|
269
|
+
return value.toLowerCase().replace(/[^a-z0-9\s]+/g, " ").replace(/\s+/g, " ").trim();
|
|
270
|
+
}
|
|
180
271
|
const SOCIAL_SURFACE_SEQUENCE = [
|
|
181
272
|
{
|
|
182
273
|
id: "feed",
|
|
@@ -220,18 +311,28 @@ const SOCIAL_SURFACE_SEQUENCE = [
|
|
|
220
311
|
},
|
|
221
312
|
];
|
|
222
313
|
async function socialWorkplanFor(args) {
|
|
223
|
-
if (
|
|
314
|
+
if (hasAnswer(args.answers, "feature_surface")) {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
const creativeHints = args.creativeSelection ? creativeSurfaceHints(args.creativeSelection) : [];
|
|
318
|
+
const useCreativeSequence = creativeHints.length > 1;
|
|
319
|
+
if (!BROAD_SOCIAL_REGEX.test(args.request) && !useCreativeSequence) {
|
|
224
320
|
return undefined;
|
|
225
321
|
}
|
|
226
322
|
const matched = SOCIAL_SURFACE_SEQUENCE.filter((surface) => surface.aliases.some((pattern) => pattern.test(args.request)));
|
|
227
|
-
const selected =
|
|
228
|
-
?
|
|
229
|
-
|
|
323
|
+
const selected = useCreativeSequence
|
|
324
|
+
? creativeHints.flatMap((hint) => {
|
|
325
|
+
const surface = SOCIAL_SURFACE_SEQUENCE.find((item) => item.id === hint.id);
|
|
326
|
+
return surface ? [{ surface, creativeHint: hint }] : [];
|
|
327
|
+
})
|
|
328
|
+
: (matched.length > 0
|
|
329
|
+
? matched
|
|
330
|
+
: SOCIAL_SURFACE_SEQUENCE.filter((surface) => surface.defaultForGenericBroad)).map((surface) => ({ surface, creativeHint: undefined }));
|
|
230
331
|
if (selected.length <= 1) {
|
|
231
332
|
return undefined;
|
|
232
333
|
}
|
|
233
334
|
const sequence = [];
|
|
234
|
-
for (const surface of selected) {
|
|
335
|
+
for (const { surface, creativeHint } of selected) {
|
|
235
336
|
const definition = getOutcomeDefinition(surface.outcome);
|
|
236
337
|
const capabilityAvailability = await platformCapabilityAvailability(surface.outcome, args.platform);
|
|
237
338
|
const surfaceAnswers = { ...args.answers, feature_surface: surface.id };
|
|
@@ -255,9 +356,9 @@ async function socialWorkplanFor(args) {
|
|
|
255
356
|
outcome: surface.outcome,
|
|
256
357
|
label: surface.label,
|
|
257
358
|
matchedPrompt,
|
|
258
|
-
reason: matchedPrompt
|
|
359
|
+
reason: creativeHint?.reason ?? (matchedPrompt
|
|
259
360
|
? `The request explicitly mentions ${surface.label.toLowerCase()}.`
|
|
260
|
-
: "The request is generic broad social work, so Vise includes this core surface in the default sequence.",
|
|
361
|
+
: "The request is generic broad social work, so Vise includes this core surface in the default sequence."),
|
|
261
362
|
planCommand: `vise plan ${commonArgs}`,
|
|
262
363
|
initCommand: `vise init ${commonArgs}`,
|
|
263
364
|
intake: {
|
|
@@ -276,7 +377,15 @@ async function socialWorkplanFor(args) {
|
|
|
276
377
|
return {
|
|
277
378
|
kind: "social-multi-surface",
|
|
278
379
|
status,
|
|
279
|
-
note:
|
|
380
|
+
note: useCreativeSequence
|
|
381
|
+
? "This accepted creative variant is decomposed into ordered per-surface plans from its experience objects. Initialize and check one surface at a time so each sidecar has one deterministic outcome, while using this sequence as the coordinated product workplan."
|
|
382
|
+
: "This broad social request is decomposed into ordered per-surface plans. Initialize and check one surface at a time so each sidecar has one outcome, while using this sequence as the coordinated product workplan.",
|
|
383
|
+
creativeContext: args.creativeSelection
|
|
384
|
+
? {
|
|
385
|
+
selectedVariant: creativeContextForPlan(args.creativeSelection).selectedVariant,
|
|
386
|
+
surfaceHints: creativeHints,
|
|
387
|
+
}
|
|
388
|
+
: undefined,
|
|
280
389
|
sequence,
|
|
281
390
|
nextStep: "Resolve each surface's blocking questions, then run the listed plan/init command for that surface before implementation. After each surface build, run `vise check .`, `vise sync .`, `vise validate .`, and `vise run-sensors .`.",
|
|
282
391
|
};
|
package/package.json
CHANGED