@amityco/social-plus-vise 0.11.0 → 0.12.2
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 +58 -0
- package/README.md +32 -1
- package/dist/capabilities.js +447 -0
- package/dist/outcomes.js +444 -2
- package/dist/server.js +76 -3
- package/dist/tools/ast.js +25 -0
- package/dist/tools/compliance.js +20 -0
- package/dist/tools/design.js +1496 -0
- package/dist/tools/docs.js +9 -4
- package/dist/tools/integration.js +83 -7
- package/dist/tools/project.js +652 -44
- package/dist/tools/sdkVersion.js +129 -0
- package/package.json +16 -3
- package/rules/comments.yaml +0 -72
- package/rules/feed.yaml +1150 -11
- package/rules/sdk-lifecycle.yaml +9 -9
- package/skills/social-plus-vise/SKILL.md +93 -93
- package/skills/social-plus-vise/reference/debugging.md +39 -0
- package/skills/social-plus-vise/reference/operations.md +59 -0
package/dist/tools/docs.js
CHANGED
|
@@ -159,25 +159,30 @@ async function loadLocalDocPages(root) {
|
|
|
159
159
|
}));
|
|
160
160
|
}
|
|
161
161
|
async function fetchText(url) {
|
|
162
|
-
|
|
162
|
+
return fetchTextWithTimeout(url, "text/plain, text/markdown, */*");
|
|
163
|
+
}
|
|
164
|
+
// Shared network primitive — same AbortController + env-configurable timeout used for
|
|
165
|
+
// docs fetches. Exported so other plan-layer lookups (e.g. the npm registry SDK-version
|
|
166
|
+
// check) reuse one network path rather than adding a parallel one.
|
|
167
|
+
export async function fetchTextWithTimeout(url, accept = "*/*", timeoutMs = fetchTimeoutMs()) {
|
|
163
168
|
const controller = new AbortController();
|
|
164
169
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
165
170
|
try {
|
|
166
171
|
const response = await fetch(url, {
|
|
167
172
|
headers: {
|
|
168
|
-
accept
|
|
173
|
+
accept,
|
|
169
174
|
"user-agent": packageUserAgent,
|
|
170
175
|
},
|
|
171
176
|
signal: controller.signal,
|
|
172
177
|
});
|
|
173
178
|
if (!response.ok) {
|
|
174
|
-
throw new Error(`Failed to fetch
|
|
179
|
+
throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
|
|
175
180
|
}
|
|
176
181
|
return await response.text();
|
|
177
182
|
}
|
|
178
183
|
catch (error) {
|
|
179
184
|
if (error instanceof Error && error.name === "AbortError") {
|
|
180
|
-
throw new Error(`Timed out fetching
|
|
185
|
+
throw new Error(`Timed out fetching ${url} after ${timeoutMs}ms.`);
|
|
181
186
|
}
|
|
182
187
|
throw error;
|
|
183
188
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { access } from "node:fs/promises";
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { BROAD_SOCIAL_REGEX, DESIGN_REGEX, classifyOutcome, getOutcomeDefinition, hasAnswer, planContextFor, } from "../outcomes.js";
|
|
4
4
|
import { objectInput, optionalStringField, stringField, textResult } from "../types.js";
|
|
5
|
+
import { capabilityChecklist } from "../capabilities.js";
|
|
5
6
|
import { applicableComplianceRuleSummaries } from "./compliance.js";
|
|
7
|
+
import { readDesignContract } from "./design.js";
|
|
8
|
+
import { sdkVersionGuidance } from "./sdkVersion.js";
|
|
6
9
|
import { detectCommandSensors } from "./harness.js";
|
|
7
10
|
import { inspectProject } from "./project.js";
|
|
8
11
|
export const planIntegrationTool = {
|
|
@@ -68,24 +71,97 @@ async function buildIntegrationPlan(repoPath, request, surfacePath, answers = {}
|
|
|
68
71
|
answers,
|
|
69
72
|
});
|
|
70
73
|
const definition = getOutcomeDefinition(outcome);
|
|
74
|
+
const intake = intakeFor(ctx, definition.intakeQuestions(ctx));
|
|
75
|
+
const designContract = await readDesignContract(repoRoot);
|
|
76
|
+
// Advisory SDK-version currency guidance (npm registry for TS/RN; version-agnostic
|
|
77
|
+
// for native). Best-effort — degrades to greenfield "install latest + pin" if the
|
|
78
|
+
// registry is unreachable. Never gates.
|
|
79
|
+
const packageJsonText = await readFile(path.join(root, "package.json"), "utf8").catch(() => undefined);
|
|
80
|
+
const sdkVersion = await sdkVersionGuidance(platform, packageJsonText);
|
|
81
|
+
// Scope decisions, hoisted to the top of the output so they survive a `head`
|
|
82
|
+
// truncation. Blocking questions must be resolved before building; clarifying
|
|
83
|
+
// questions (e.g. which engagement surfaces are in scope) must be decided and
|
|
84
|
+
// the decision stated — so an omitted feature like comments is an explicit,
|
|
85
|
+
// reviewable choice rather than a silent drop. Mirrors the detailed `intake`
|
|
86
|
+
// block below; placed here because the intake block lands past common `head`
|
|
87
|
+
// cut points.
|
|
88
|
+
const decisionsRequired = intake.questions.map((q) => q.blocksImplementationWhenMissing
|
|
89
|
+
? `[resolve before building] ${q.question}`
|
|
90
|
+
: `[decide & state in your summary] ${q.question}`);
|
|
91
|
+
// Steps-first ordering: implementationSteps + validation lead the object so
|
|
92
|
+
// that an agent piping `vise plan` through `head` still captures the
|
|
93
|
+
// actionable guidance. The verbose scaffolding (intake, docs, surfaces, rule
|
|
94
|
+
// dumps) follows. Do not move implementationSteps back down — feature steps
|
|
95
|
+
// landing past a `head -120` cut is a documented real-world failure mode.
|
|
71
96
|
return {
|
|
72
97
|
outcome,
|
|
73
98
|
platform,
|
|
74
|
-
surface: inspection.selectedSurface ? { path: inspection.selectedSurface.path, platforms: inspection.selectedSurface.platforms } : undefined,
|
|
75
|
-
availableSurfaces: inspection.surfaces,
|
|
76
99
|
supportLevel,
|
|
77
100
|
intent: intentFor(request, definition.interpretation),
|
|
78
|
-
|
|
79
|
-
|
|
101
|
+
decisionsRequired,
|
|
102
|
+
implementationSteps: definition.implementationSteps(ctx),
|
|
103
|
+
validation: ["validate_setup", "run_sensors", ...definition.validation(platform)],
|
|
104
|
+
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.",
|
|
80
105
|
requiredInputs: composeRequiredInputs(ctx, definition.requiredInputs(ctx)),
|
|
81
106
|
targetFiles: await targetFilesFor(root, outcome, platform, inspection.designSignals),
|
|
82
107
|
implementationRules: composeImplementationRules(ctx, definition.implementationRules(ctx)),
|
|
83
|
-
|
|
84
|
-
|
|
108
|
+
intake,
|
|
109
|
+
docs: definition.docs(platform).filter((doc) => doc.path !== "unknown"),
|
|
110
|
+
surface: inspection.selectedSurface ? { path: inspection.selectedSurface.path, platforms: inspection.selectedSurface.platforms } : undefined,
|
|
111
|
+
availableSurfaces: inspection.surfaces,
|
|
85
112
|
applicableRules: await applicableComplianceRuleSummaries(outcome, inspection.platforms),
|
|
86
113
|
sensors: sensors.map((sensor) => ({ name: sensor.name, command: sensor.command, source: sensor.source })),
|
|
87
114
|
stopConditions: composeStopConditions(ctx, definition.stopConditions(ctx), inspection.surfaces, surfacePath),
|
|
88
115
|
evidencePolicy: "Every implementation step must cite at least one detected file, docs page, validator rule, or required user input. If evidence is missing, stop and ask the user instead of inventing details.",
|
|
116
|
+
designContract: designContract ? designContractGuidance(designContract) : undefined,
|
|
117
|
+
completenessChecklist: completenessChecklistFor(outcome),
|
|
118
|
+
sdkVersion,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Vise-authored capability checklist for the outcome (feed-forward). The agent
|
|
122
|
+
// builds each or opts out with a recorded reason (`// vise: scope-omit <id>
|
|
123
|
+
// <reason>`), which `vise check` reads and reports. Advisory — Vise proposes the
|
|
124
|
+
// set so completeness doesn't depend on the agent remembering it.
|
|
125
|
+
function completenessChecklistFor(outcome) {
|
|
126
|
+
const items = capabilityChecklist(outcome);
|
|
127
|
+
if (items.length === 0) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
note: "Build each capability, or opt out with `// vise: scope-omit <id> <reason>`. `vise check` reports present/missing/opted-out (advisory — never fails the check).",
|
|
132
|
+
capabilities: items,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// Build advisory UI-generation guidance from an extracted design contract.
|
|
136
|
+
// Declared tokens are surfaced with their custom-property name (so the agent
|
|
137
|
+
// references `var(--x)` / maps it per platform); inferred tokens carry their
|
|
138
|
+
// raw value plus a usage count and an explicit "inferred" marker so they are
|
|
139
|
+
// never mistaken for authoritative brand values.
|
|
140
|
+
function designContractGuidance(contract) {
|
|
141
|
+
const byCategory = (category) => contract.tokens
|
|
142
|
+
.filter((token) => token.category === category)
|
|
143
|
+
.map((token) => token.provenance === "declared" && token.name
|
|
144
|
+
? `${token.name}: ${token.value}`
|
|
145
|
+
: `${token.value} (inferred, ${token.uses}×)`);
|
|
146
|
+
return {
|
|
147
|
+
digest: contract.digest,
|
|
148
|
+
strength: contract.stats.strength,
|
|
149
|
+
source: contract.source,
|
|
150
|
+
summary: `A design contract was extracted from the customer's prototype (${contract.stats.declared_tokens} declared + ${contract.stats.inferred_tokens} inferred tokens, strength: ${contract.stats.strength}). ` +
|
|
151
|
+
"Build the social.plus UI using these tokens so it matches the prototype's aesthetic. Prefer the declared tokens; treat inferred tokens as advisory and confirm brand values with the customer when the contract is weak.",
|
|
152
|
+
tokens: {
|
|
153
|
+
color: byCategory("color"),
|
|
154
|
+
spacing: byCategory("space"),
|
|
155
|
+
radius: byCategory("radius"),
|
|
156
|
+
shadow: byCategory("shadow"),
|
|
157
|
+
fontFamily: byCategory("fontFamily"),
|
|
158
|
+
fontSize: byCategory("fontSize"),
|
|
159
|
+
motion: byCategory("motion"),
|
|
160
|
+
},
|
|
161
|
+
components: contract.components.map((component) => ({ name: component.name, selector: component.selector })),
|
|
162
|
+
breakpoints: contract.breakpoints.map((breakpoint) => breakpoint.raw),
|
|
163
|
+
attestation: `When you record a design attestation, cite this contract digest (${contract.digest}) so the generated feed can be claimed conformant to the customer's prototype.`,
|
|
164
|
+
advisoryOnly: "This contract is advisory generation guidance — it adds no deterministic enforcement and never fails `vise check`.",
|
|
89
165
|
};
|
|
90
166
|
}
|
|
91
167
|
function intentFor(request, interpretation) {
|