@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/ast.js
CHANGED
|
@@ -67,13 +67,38 @@ function getParser(language) {
|
|
|
67
67
|
}
|
|
68
68
|
return parser;
|
|
69
69
|
}
|
|
70
|
+
// node-tree-sitter's native parser rejects sufficiently large inputs with a
|
|
71
|
+
// native "Invalid argument" error (~32KB string limit). It IS catchable, but an
|
|
72
|
+
// unguarded caller would otherwise abort the whole validate run. We short-circuit
|
|
73
|
+
// before the native call so callers get a clean, documented, catchable error and
|
|
74
|
+
// can degrade to regex-only for that file. Real codebases routinely have files
|
|
75
|
+
// past this size (1000+ line activities/view controllers).
|
|
76
|
+
export const MAX_PARSE_BYTES = 30000;
|
|
70
77
|
/**
|
|
71
78
|
* Parse source content into a tree-sitter syntax tree.
|
|
79
|
+
* Throws on oversized input (see MAX_PARSE_BYTES) — callers that want graceful
|
|
80
|
+
* degradation should use tryParse or wrap this in try/catch.
|
|
72
81
|
*/
|
|
73
82
|
export function parse(language, source) {
|
|
83
|
+
if (Buffer.byteLength(source, "utf8") > MAX_PARSE_BYTES) {
|
|
84
|
+
throw new Error(`source exceeds tree-sitter parse limit (${Buffer.byteLength(source, "utf8")} bytes > ${MAX_PARSE_BYTES})`);
|
|
85
|
+
}
|
|
74
86
|
const parser = getParser(language);
|
|
75
87
|
return parser.parse(source);
|
|
76
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse, returning null instead of throwing when the source can't be parsed
|
|
91
|
+
* (oversized input, native parser error). Lets validators skip AST analysis for
|
|
92
|
+
* one file and fall back to regex without aborting the run.
|
|
93
|
+
*/
|
|
94
|
+
export function tryParse(language, source) {
|
|
95
|
+
try {
|
|
96
|
+
return parse(language, source);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
77
102
|
/**
|
|
78
103
|
* Find all call expressions in the tree whose callee matches a pattern.
|
|
79
104
|
* Returns normalised callee strings and argument nodes.
|
package/dist/tools/compliance.js
CHANGED
|
@@ -2,9 +2,11 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { assessProjectCompleteness } from "../capabilities.js";
|
|
5
6
|
import { classifyOutcome } from "../outcomes.js";
|
|
6
7
|
import { objectInput, optionalStringField, stringField, textResult } from "../types.js";
|
|
7
8
|
import { packageVersion } from "../version.js";
|
|
9
|
+
import { readDesignContract } from "./design.js";
|
|
8
10
|
import { inspectProject, validateSetup } from "./project.js";
|
|
9
11
|
const complianceDirName = "sp-vise";
|
|
10
12
|
const attestationsDirName = "attestations";
|
|
@@ -230,6 +232,7 @@ export async function initCompliance(repoPath, request, surfacePath) {
|
|
|
230
232
|
const refs = rules.map(ruleRef); // minimal shape — stable digest input
|
|
231
233
|
const fileRefs = rules.map(ruleRefForFile); // adds title for human/agent readers
|
|
232
234
|
const engagement = await readEngagement(repoRoot);
|
|
235
|
+
const designContract = await readDesignContract(repoRoot);
|
|
233
236
|
const compliance = {
|
|
234
237
|
schema_version: schemaVersion,
|
|
235
238
|
foundry_version: packageVersion,
|
|
@@ -240,6 +243,15 @@ export async function initCompliance(repoPath, request, surfacePath) {
|
|
|
240
243
|
engagement_id: engagement?.engagement_id,
|
|
241
244
|
surface: inspection.selectedSurface ? { path: inspection.selectedSurface.path, platforms: inspection.selectedSurface.platforms } : undefined,
|
|
242
245
|
rules: fileRefs, // file carries titles
|
|
246
|
+
design_contract: designContract
|
|
247
|
+
? {
|
|
248
|
+
digest: designContract.digest,
|
|
249
|
+
strength: designContract.stats.strength,
|
|
250
|
+
source_kind: designContract.source.kind,
|
|
251
|
+
declared_tokens: designContract.stats.declared_tokens,
|
|
252
|
+
inferred_tokens: designContract.stats.inferred_tokens,
|
|
253
|
+
}
|
|
254
|
+
: undefined,
|
|
243
255
|
};
|
|
244
256
|
await mkdir(attestationsDir(repoRoot), { recursive: true });
|
|
245
257
|
await writeJson(compliancePath(repoRoot), compliance);
|
|
@@ -267,6 +279,7 @@ export async function initCompliance(repoPath, request, surfacePath) {
|
|
|
267
279
|
surfacePath: inspection.selectedSurface?.path,
|
|
268
280
|
rules: refs.length,
|
|
269
281
|
engagement_id: engagement?.engagement_id,
|
|
282
|
+
...(compliance.design_contract && { design_contract: compliance.design_contract }),
|
|
270
283
|
...(warnings.length > 0 && { warnings }),
|
|
271
284
|
nextStep: "Run vise check, then implement until rules pass deterministically or are attested.",
|
|
272
285
|
};
|
|
@@ -426,6 +439,10 @@ export async function checkCompliance(repoPath) {
|
|
|
426
439
|
const needsAttestation = results.some((result) => result.status === "attestation-needed" || result.status === "stale");
|
|
427
440
|
// Precedence: blocked (exit 3) > deterministic-failures (2) > needs-attestation (1) > green (0).
|
|
428
441
|
// Contract drift (exit 4) is handled earlier and short-circuits the loop.
|
|
442
|
+
// Advisory feature-completeness — surfaced but NEVER part of status/exitCode
|
|
443
|
+
// (completeness is a "this is missing" claim, structurally FP-prone; see the
|
|
444
|
+
// validation-boundaries principle). Failure to assess is silently ignored.
|
|
445
|
+
const completeness = (await assessProjectCompleteness(inspection.effectiveRoot, compliance.outcome).catch(() => null)) ?? undefined;
|
|
429
446
|
// Blocked wins because the agent cannot proceed without customer input;
|
|
430
447
|
// surfacing a smaller failure first would distract from the real blocker.
|
|
431
448
|
return {
|
|
@@ -441,6 +458,7 @@ export async function checkCompliance(repoPath) {
|
|
|
441
458
|
surfacePath: compliance.surface?.path,
|
|
442
459
|
summary,
|
|
443
460
|
rules: results,
|
|
461
|
+
...(completeness && (completeness.missing.length > 0 || completeness.optedOut.length > 0 || completeness.present.length > 0) ? { completeness } : {}),
|
|
444
462
|
};
|
|
445
463
|
}
|
|
446
464
|
export async function syncCompliance(repoPath) {
|
|
@@ -537,12 +555,14 @@ export async function statusCompliance(repoPath) {
|
|
|
537
555
|
const repoRoot = path.resolve(repoPath);
|
|
538
556
|
const check = await checkCompliance(repoPath);
|
|
539
557
|
const engagement = await readEngagement(repoRoot);
|
|
558
|
+
const compliance = await readCompliance(repoRoot).catch(() => null);
|
|
540
559
|
return {
|
|
541
560
|
status: check.status,
|
|
542
561
|
exitCode: check.exitCode,
|
|
543
562
|
outcome: check.outcome,
|
|
544
563
|
surfacePath: check.surfacePath,
|
|
545
564
|
summary: check.summary,
|
|
565
|
+
...(compliance?.design_contract && { design_contract: compliance.design_contract }),
|
|
546
566
|
...(engagement && {
|
|
547
567
|
engagement: {
|
|
548
568
|
engagement_id: engagement.engagement_id,
|