@amityco/social-plus-vise 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -2
- package/README.md +23 -10
- package/dist/capabilities.js +35 -4
- package/dist/entryState.js +71 -0
- package/dist/experience.js +70 -0
- package/dist/explore.js +51 -0
- package/dist/flow.js +382 -0
- package/dist/humanFormat.js +251 -0
- package/dist/intake.js +117 -0
- package/dist/intelligence/placement.js +2 -1
- package/dist/outcomes.js +141 -42
- package/dist/productExpectations.js +15 -0
- package/dist/requestReadiness.js +99 -0
- package/dist/server.js +675 -56
- package/dist/sidecar.js +5 -0
- package/dist/solutionPath.js +2 -2
- package/dist/tools/compliance.js +1014 -133
- package/dist/tools/creative.js +14 -12
- package/dist/tools/debug.js +83 -26
- package/dist/tools/design.js +344 -14
- package/dist/tools/experienceCompiler.js +1 -1
- package/dist/tools/experienceSensors.js +1 -1
- package/dist/tools/harness.js +13 -0
- package/dist/tools/integration.js +263 -90
- package/dist/tools/learning.js +1 -3
- package/dist/tools/project.js +987 -72
- package/dist/tools/sdkFacts.js +8 -1
- package/dist/tools/smoke.js +134 -0
- package/dist/tools/uxHarness.js +54 -6
- package/dist/uikitCustomization.js +22 -6
- package/dist/version.js +7 -3
- package/package.json +1 -1
- package/packages/intelligence/catalog/catalog.schema.json +1 -1
- package/packages/intelligence/catalog/experience-objects.json +2 -2
- package/packages/intelligence/catalog/variants.json +24 -0
- package/rules/event.yaml +3 -0
- package/rules/feed.yaml +251 -0
- package/rules/invitation.yaml +4 -0
- package/rules/live-data.yaml +110 -0
- package/rules/notification-tray.yaml +4 -0
- package/rules/poll.yaml +5 -0
- package/rules/sdk-lifecycle.yaml +559 -0
- package/rules/search.yaml +5 -0
- package/rules/security.yaml +12 -0
- package/rules/story.yaml +5 -0
- package/rules/user-blocking.yaml +5 -0
- package/skills/social-plus-vise/SKILL.md +163 -15
package/dist/tools/creative.js
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { platformCapabilityAvailability } from "../capabilities.js";
|
|
6
|
+
import { platformFeatureGapsForObjects } from "../outcomes.js";
|
|
6
7
|
import { objectInput, optionalBooleanField, optionalStringField, stringField, textResult } from "../types.js";
|
|
7
8
|
import { packageVersion } from "../version.js";
|
|
8
9
|
import { inspectProject } from "./project.js";
|
|
@@ -195,27 +196,27 @@ export async function buildCreativeBrief(options) {
|
|
|
195
196
|
candidateSolutions: candidates,
|
|
196
197
|
selectionGuidance: {
|
|
197
198
|
mode: "agent-grounded-selection",
|
|
198
|
-
instruction: "You (the driving agent) choose the best-fitting variant by reasoning over candidateSolutions and the request. Use each candidate's `description` and `whenToChoose` (self-describing selecting signals) to discriminate between close variants — match the signals present in the request to the variant whose `whenToChoose` they satisfy. The listed order and the `fallbackDefault` flag are advisory keyword-derived hints, not recommendations to follow — keyword matching can point at the wrong variant for off-keyword requests, so decide by semantic fit. Vise will validate (ground) your choice against the catalog; it does not infer the variant for you.",
|
|
199
|
+
instruction: "You (the driving agent) choose the best-fitting variant by reasoning over candidateSolutions and the request. Use each candidate's `description` and `whenToChoose` (self-describing selecting signals) to discriminate between close variants — match the signals present in the request to the variant whose `whenToChoose` they satisfy. Before accepting a variant, present an EI choice block to the user: recommended experience, 2-3 concrete request/project signals, 2-3 credible alternatives with when-to-choose/tradeoffs, expected blueprint surfaces/objects, and the no-fit option. Do not collapse EI into a one-sentence recommendation or accept before the choice is visible. The listed order and the `fallbackDefault` flag are advisory keyword-derived hints, not recommendations to follow — keyword matching can point at the wrong variant for off-keyword requests, so decide by semantic fit. Vise will validate (ground) your choice against the catalog; it does not infer the variant for you.",
|
|
199
200
|
howToAccept: "vise creative accept <repoPath> --variant <candidate id> --rationale \"<one line, grounded in the request and catalog>\" --confidence high|medium|low",
|
|
200
201
|
contract: {
|
|
201
202
|
variant: "A candidateSolutions id chosen by best fit to the request (not by listed order or the fallbackDefault flag).",
|
|
202
203
|
fallbackDefault: "One candidate carries fallbackDefault=true: the keyword top, used as the default ONLY when no agent makes a grounded selection. Do not defer to it; decide by fit.",
|
|
203
204
|
rationale: "Required: one line explaining, grounded in the request and the candidate's catalog fit, why this variant. A selection without a rationale is rejected.",
|
|
204
205
|
confidence: "high | medium | low. Use low when the request is vague or genuinely split between variants; low/missing confidence is recorded as a review signal, not a failure.",
|
|
205
|
-
noFit: "If no candidate genuinely fits the request, do not force one. Record the no-fit instead: `vise creative accept <repoPath> --variant none --rationale \"<what the catalog is missing>\" [--closest <nearest variant id>]`. This writes a local catalog-gap record for human review (it does not change the catalog or upload anything); it is a signal the catalog may need a new variant.",
|
|
206
|
+
noFit: "If no candidate genuinely fits the request, do not force one. Record the no-fit instead: `vise creative accept <repoPath> --variant none --rationale \"<what the catalog is missing>\" --confidence high|medium|low [--closest <nearest variant id>]`. This writes a local catalog-gap record for human review (it does not change the catalog or upload anything); it is a signal the catalog may need a new variant.",
|
|
206
207
|
},
|
|
207
208
|
},
|
|
208
209
|
questions: [
|
|
209
210
|
{
|
|
210
211
|
id: "preferred_solution",
|
|
211
|
-
question: "Which
|
|
212
|
+
question: "Which EI experience should be selected after presenting the recommendation, alternatives, tradeoffs, expected blueprint surfaces, and no-fit option?",
|
|
212
213
|
why: "Creative mode proposes product/UX directions. The driving agent selects the best-fitting variant and accepts it with a grounded rationale and confidence (see selectionGuidance); normal Vise planning starts only after a variant is accepted.",
|
|
213
214
|
required: true,
|
|
214
215
|
blocksImplementationWhenMissing: true,
|
|
215
216
|
options: candidates.map((candidate) => candidate.id),
|
|
216
217
|
},
|
|
217
218
|
],
|
|
218
|
-
nextStep: "
|
|
219
|
+
nextStep: "Present the EI choice block first: recommended experience, concrete fit signals, credible alternatives/tradeoffs, expected blueprint surfaces/objects, and no-fit option. Then choose the best-fitting variant by reasoning over candidateSolutions (listed order is advisory) and accept it with a grounded rationale and confidence: `vise creative accept <repoPath> --variant <id> --rationale \"<why>\" --confidence high|medium|low`. Vise validates the selection against the catalog. If no candidate genuinely fits, record a no-fit instead of forcing a choice: `vise creative accept <repoPath> --variant none --rationale \"<what is missing>\" --confidence high|medium|low`.",
|
|
219
220
|
};
|
|
220
221
|
if (options.rankingPreview === true) {
|
|
221
222
|
brief.candidateRankingPreview = buildCandidateRankingPreview(brief);
|
|
@@ -242,12 +243,9 @@ export async function acceptCreativeVariant(options) {
|
|
|
242
243
|
if (!selected) {
|
|
243
244
|
throw new Error(`Creative variant "${variantId}" was not found in ${repoRelativePath(repoRoot, briefPath)}. Available variants: ${brief.candidateSolutions.map((candidate) => candidate.id).join(", ") || "(none)"}.`);
|
|
244
245
|
}
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
if (grounding.status === "rejected") {
|
|
249
|
-
throw new Error(`Grounded selection for "${variantId}" was rejected: ${grounding.signals.filter((signal) => signal.severity === "error").map((signal) => signal.message).join(" ")}`);
|
|
250
|
-
}
|
|
246
|
+
const grounding = groundSelection({ variantId, rationale: options.rationale, confidence: options.confidence }, brief.candidateSolutions.map((candidate) => candidate.id));
|
|
247
|
+
if (grounding.status === "rejected") {
|
|
248
|
+
throw new Error(`Grounded selection for "${variantId}" was rejected: ${grounding.signals.filter((signal) => signal.severity === "error").map((signal) => signal.message).join(" ")}`);
|
|
251
249
|
}
|
|
252
250
|
const selection = {
|
|
253
251
|
schema_version: CREATIVE_SELECTION_SCHEMA_VERSION,
|
|
@@ -263,7 +261,7 @@ export async function acceptCreativeVariant(options) {
|
|
|
263
261
|
},
|
|
264
262
|
objective: brief.objective,
|
|
265
263
|
selectedVariant: selected,
|
|
266
|
-
|
|
264
|
+
grounding,
|
|
267
265
|
implementationContext: {
|
|
268
266
|
planRequest: `${selected.title}: ${brief.request}`,
|
|
269
267
|
surfaceHints: creativeSurfaceHints(selected),
|
|
@@ -560,9 +558,13 @@ async function feasibilityForVariant(variant, inspection) {
|
|
|
560
558
|
if (outcomes.length === 0) {
|
|
561
559
|
notes.push("No current Vise outcome maps directly to this variant yet; treat it as exploratory product guidance.");
|
|
562
560
|
}
|
|
561
|
+
const objectGaps = platform === "unknown" ? [] : platformFeatureGapsForObjects(variant.experienceObjectIds, platform);
|
|
562
|
+
for (const { gap, objects } of objectGaps) {
|
|
563
|
+
notes.push(`References experience object(s) ${objects.join(", ")} not available in the ${platform} SDK (${gap.feature} — available on ${gap.availableOn.join("/")}). See platformAvailability; this variant is not buildable as specified on ${platform}.`);
|
|
564
|
+
}
|
|
563
565
|
return {
|
|
564
566
|
platform,
|
|
565
|
-
support: supportFor(outcomeResults, customObjectIds),
|
|
567
|
+
support: objectGaps.length > 0 ? "references-unavailable-objects" : supportFor(outcomeResults, customObjectIds),
|
|
566
568
|
outcomes: outcomeResults,
|
|
567
569
|
customObjectIds,
|
|
568
570
|
notes,
|
package/dist/tools/debug.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import { objectInput, optionalBooleanField, stringField, textResult } from "../types.js";
|
|
2
4
|
import { checkCompliance, rulesById } from "./compliance.js";
|
|
3
5
|
import { inspectProject } from "./project.js";
|
|
@@ -23,48 +25,94 @@ export async function debugIssue(repoPath, errorMessage, options = {}) {
|
|
|
23
25
|
if (errorMessage.includes("method not found") || errorMessage.includes("Unresolved reference")) {
|
|
24
26
|
likelyCause = "Potential Version Mismatch: The codebase is using a newer API pattern against an older SDK version installed in the project.";
|
|
25
27
|
}
|
|
28
|
+
const missingModuleMatch = /Cannot find module ['"]([^'"]+)['"]/.exec(errorMessage)
|
|
29
|
+
?? (/\bMODULE_NOT_FOUND\b/.test(errorMessage) ? /['"]([^'"]+)['"]/.exec(errorMessage) : null);
|
|
30
|
+
const missingModulePkg = missingModuleMatch && missingModuleMatch[1] && !/^[./]/.test(missingModuleMatch[1])
|
|
31
|
+
? missingModuleMatch[1]
|
|
32
|
+
: undefined;
|
|
26
33
|
const correlatedRules = [];
|
|
27
34
|
let checkResult = null;
|
|
28
35
|
try {
|
|
29
36
|
checkResult = await checkCompliance(repoPath);
|
|
30
37
|
const rulesMap = await rulesById();
|
|
31
38
|
for (const rule of checkResult.rules) {
|
|
39
|
+
const contractRuleId = rule.contractRuleId ?? rule.ruleId;
|
|
40
|
+
const ruleDef = rulesMap.get(contractRuleId);
|
|
41
|
+
const symptoms = ruleDef?.symptoms || [];
|
|
42
|
+
if (symptoms.length === 0 || !symptoms.some((s) => errorMessage.includes(s))) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
32
45
|
if (rule.status === "deterministic-fail" || rule.status === "attestation-needed") {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ruleId: rule.ruleId,
|
|
39
|
-
status: "failed",
|
|
40
|
-
impact: `This rule is currently failing and its known symptoms match the crash log.`,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
46
|
+
correlatedRules.push({
|
|
47
|
+
ruleId: rule.ruleId,
|
|
48
|
+
status: "failed",
|
|
49
|
+
impact: `This rule is currently failing and its known symptoms match the crash log.`,
|
|
50
|
+
});
|
|
43
51
|
}
|
|
44
52
|
else if (rule.status === "attested") {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
correlatedRules.push({
|
|
54
|
+
ruleId: rule.ruleId,
|
|
55
|
+
status: "attested",
|
|
56
|
+
attestation: rule.attestation,
|
|
57
|
+
impact: `Warning: This rule was attested as passing, but a matching runtime exception was detected. The custom implementation may be flawed.`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
correlatedRules.push({
|
|
62
|
+
ruleId: rule.ruleId,
|
|
63
|
+
status: rule.status,
|
|
64
|
+
impact: `This rule's known symptoms match the crash log even though its compliance status is "${rule.status}". The deterministic check did not catch this, so the failure is likely runtime-only or outside the sensor's reach — review the implementation.`,
|
|
65
|
+
});
|
|
56
66
|
}
|
|
57
67
|
}
|
|
58
68
|
}
|
|
59
69
|
catch (err) {
|
|
60
70
|
}
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
const failingCorrelated = correlatedRules.filter((r) => r.status === "failed" || r.status === "attested");
|
|
72
|
+
const moduleDiagnosis = missingModulePkg
|
|
73
|
+
? (() => {
|
|
74
|
+
const projectRoot = path.resolve(repoPath);
|
|
75
|
+
const pkg = missingModulePkg;
|
|
76
|
+
if (!existsSync(path.join(projectRoot, "node_modules"))) {
|
|
77
|
+
return {
|
|
78
|
+
cause: `Dependencies are not installed — node_modules is absent at ${projectRoot}, so "${pkg}" cannot be resolved. This is a setup/environment issue, not a code defect.`,
|
|
79
|
+
hint: `Run \`npm install\` at the project root to install declared dependencies, then retry. If "${pkg}" is not yet a dependency, add it: \`npm install ${pkg}\`.`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (!existsSync(path.join(projectRoot, "node_modules", ...pkg.split("/")))) {
|
|
83
|
+
return {
|
|
84
|
+
cause: `The module "${pkg}" is not present in node_modules, so it cannot be resolved. This is a missing-dependency issue, not a code defect.`,
|
|
85
|
+
hint: `Install it at the project root: \`npm install ${pkg}\`, then retry. (If it should already be installed, delete node_modules and re-run \`npm install\`.)`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
cause: `The module "${pkg}" could not be resolved at runtime even though it appears installed. Confirm it is declared in package.json and the install is intact.`,
|
|
90
|
+
hint: `Re-run \`npm install\` to repair the dependency tree; if "${pkg}" is missing from package.json, add it with \`npm install ${pkg}\`.`,
|
|
91
|
+
};
|
|
92
|
+
})()
|
|
93
|
+
: undefined;
|
|
94
|
+
let missingModuleHint;
|
|
95
|
+
let secondaryModuleNote;
|
|
96
|
+
if (!likelyCause && failingCorrelated.length > 0) {
|
|
97
|
+
likelyCause = `The crash is likely caused by the non-compliant implementation of ${failingCorrelated.map(r => r.ruleId).join(", ")}.`;
|
|
98
|
+
if (moduleDiagnosis)
|
|
99
|
+
secondaryModuleNote = moduleDiagnosis.hint;
|
|
100
|
+
}
|
|
101
|
+
else if (!likelyCause && moduleDiagnosis) {
|
|
102
|
+
likelyCause = moduleDiagnosis.cause;
|
|
103
|
+
missingModuleHint = moduleDiagnosis.hint;
|
|
104
|
+
}
|
|
105
|
+
else if (!likelyCause && correlatedRules.length > 0) {
|
|
106
|
+
likelyCause = `The crash symptoms match the known signatures of ${correlatedRules.map(r => r.ruleId).join(", ")}, but ${correlatedRules.length === 1 ? "that rule passes its" : "those rules pass their"} compliance check — the cause is likely runtime-only or outside the deterministic sensor's reach.`;
|
|
63
107
|
}
|
|
64
108
|
else if (!likelyCause) {
|
|
65
109
|
likelyCause = `An unknown ${exceptionClass || "runtime"} error occurred.`;
|
|
110
|
+
if (moduleDiagnosis)
|
|
111
|
+
secondaryModuleNote = moduleDiagnosis.hint;
|
|
66
112
|
}
|
|
67
|
-
const suggestedRemediation =
|
|
113
|
+
const suggestedRemediation = missingModuleHint
|
|
114
|
+
? { action: missingModuleHint }
|
|
115
|
+
: buildRemediation(correlatedRules, checkResult);
|
|
68
116
|
const repairBrief = buildRepairBrief(correlatedRules, checkResult, inspection.platforms, likelyCause);
|
|
69
117
|
const payload = {
|
|
70
118
|
correlatedRules,
|
|
@@ -73,6 +121,7 @@ export async function debugIssue(repoPath, errorMessage, options = {}) {
|
|
|
73
121
|
extractedException: exceptionClass,
|
|
74
122
|
suggestedRemediation,
|
|
75
123
|
repairBrief,
|
|
124
|
+
...(secondaryModuleNote ? { secondaryNotes: [secondaryModuleNote] } : {}),
|
|
76
125
|
relevantDocs: [
|
|
77
126
|
{
|
|
78
127
|
title: "Troubleshooting",
|
|
@@ -85,6 +134,7 @@ export async function debugIssue(repoPath, errorMessage, options = {}) {
|
|
|
85
134
|
likelyCause: payload.likelyCause,
|
|
86
135
|
correlatedRules: payload.correlatedRules,
|
|
87
136
|
repairBrief: payload.repairBrief,
|
|
137
|
+
...(secondaryModuleNote ? { secondaryNotes: [secondaryModuleNote] } : {}),
|
|
88
138
|
relevantDocs: payload.relevantDocs,
|
|
89
139
|
};
|
|
90
140
|
}
|
|
@@ -106,8 +156,12 @@ function buildRemediation(correlatedRules, checkResult) {
|
|
|
106
156
|
docRef: `vise explain ${cr.ruleId}`,
|
|
107
157
|
};
|
|
108
158
|
});
|
|
159
|
+
const failing = correlatedRules.filter((cr) => cr.status === "failed" || cr.status === "attested");
|
|
160
|
+
const action = failing.length > 0
|
|
161
|
+
? "Repair the compliance failure(s) identified above."
|
|
162
|
+
: "The correlated rule(s) pass their deterministic compliance checks; investigate the runtime behavior of the listed rule(s). The failure is likely runtime-only or outside the sensor's reach — do not change the compliant code paths.";
|
|
109
163
|
return {
|
|
110
|
-
action
|
|
164
|
+
action,
|
|
111
165
|
rules,
|
|
112
166
|
};
|
|
113
167
|
}
|
|
@@ -143,7 +197,10 @@ function buildRepairBrief(correlatedRules, checkResult, platforms, likelyCause)
|
|
|
143
197
|
}
|
|
144
198
|
function pickPrimaryRuleId(correlatedRules) {
|
|
145
199
|
const failed = correlatedRules.find((rule) => rule.status === "failed");
|
|
146
|
-
|
|
200
|
+
if (failed)
|
|
201
|
+
return failed.ruleId;
|
|
202
|
+
const attested = correlatedRules.find((rule) => rule.status === "attested");
|
|
203
|
+
return attested?.ruleId ?? null;
|
|
147
204
|
}
|
|
148
205
|
function candidateFilesForRule(ruleId, checkResult) {
|
|
149
206
|
if (!checkResult) {
|