@sxl-studio/bridge 1.7.2 → 1.7.3
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/README.md +342 -16
- package/dist/agent-recipes.d.ts +781 -11
- package/dist/agent-recipes.js +886 -13
- package/dist/agent-recipes.js.map +1 -1
- package/dist/agent-runbook.d.ts +50 -0
- package/dist/agent-runbook.js +243 -0
- package/dist/agent-runbook.js.map +1 -0
- package/dist/asset-upload.d.ts +63 -0
- package/dist/asset-upload.js +225 -0
- package/dist/asset-upload.js.map +1 -0
- package/dist/audit-store.d.ts +15 -0
- package/dist/audit-store.js +100 -0
- package/dist/audit-store.js.map +1 -0
- package/dist/audit.d.ts +4 -3
- package/dist/audit.js +37 -4
- package/dist/audit.js.map +1 -1
- package/dist/auth.d.ts +8 -1
- package/dist/auth.js +41 -1
- package/dist/auth.js.map +1 -1
- package/dist/bridge-agent-workflow-validation-cli.d.ts +2 -0
- package/dist/bridge-agent-workflow-validation-cli.js +68 -0
- package/dist/bridge-agent-workflow-validation-cli.js.map +1 -0
- package/dist/bridge-agent-workflow-validation.d.ts +42 -0
- package/dist/bridge-agent-workflow-validation.js +170 -0
- package/dist/bridge-agent-workflow-validation.js.map +1 -0
- package/dist/bridge-contract-audit.d.ts +45 -0
- package/dist/bridge-contract-audit.js +345 -0
- package/dist/bridge-contract-audit.js.map +1 -0
- package/dist/bridge-health-cli.d.ts +2 -0
- package/dist/bridge-health-cli.js +115 -0
- package/dist/bridge-health-cli.js.map +1 -0
- package/dist/bridge-health.d.ts +33 -0
- package/dist/bridge-health.js +594 -0
- package/dist/bridge-health.js.map +1 -0
- package/dist/bridge-live-validation-cli.d.ts +2 -0
- package/dist/bridge-live-validation-cli.js +114 -0
- package/dist/bridge-live-validation-cli.js.map +1 -0
- package/dist/bridge-live-validation.d.ts +39 -0
- package/dist/bridge-live-validation.js +1141 -0
- package/dist/bridge-live-validation.js.map +1 -0
- package/dist/bridge-performance-profile.d.ts +81 -0
- package/dist/bridge-performance-profile.js +227 -0
- package/dist/bridge-performance-profile.js.map +1 -0
- package/dist/bridge-readiness-cli.d.ts +30 -0
- package/dist/bridge-readiness-cli.js +242 -0
- package/dist/bridge-readiness-cli.js.map +1 -0
- package/dist/bridge-runtime-summary.d.ts +50 -0
- package/dist/bridge-runtime-summary.js +112 -0
- package/dist/bridge-runtime-summary.js.map +1 -0
- package/dist/bridge-workflow-smoke-cli.d.ts +2 -0
- package/dist/bridge-workflow-smoke-cli.js +126 -0
- package/dist/bridge-workflow-smoke-cli.js.map +1 -0
- package/dist/bridge-workflow-smoke.d.ts +39 -0
- package/dist/bridge-workflow-smoke.js +431 -0
- package/dist/bridge-workflow-smoke.js.map +1 -0
- package/dist/codeconnect-suggestions.d.ts +74 -0
- package/dist/codeconnect-suggestions.js +398 -0
- package/dist/codeconnect-suggestions.js.map +1 -0
- package/dist/codeconnect-template.d.ts +98 -0
- package/dist/codeconnect-template.js +280 -0
- package/dist/codeconnect-template.js.map +1 -0
- package/dist/command-queue.d.ts +11 -1
- package/dist/command-queue.js +200 -1
- package/dist/command-queue.js.map +1 -1
- package/dist/command-safety.d.ts +13 -0
- package/dist/command-safety.js +59 -0
- package/dist/command-safety.js.map +1 -0
- package/dist/enabled-library-search.d.ts +49 -0
- package/dist/enabled-library-search.js +151 -0
- package/dist/enabled-library-search.js.map +1 -0
- package/dist/figma-mcp-parity.d.ts +49 -0
- package/dist/figma-mcp-parity.js +368 -0
- package/dist/figma-mcp-parity.js.map +1 -0
- package/dist/figma-mcp-skills-parity.d.ts +61 -0
- package/dist/figma-mcp-skills-parity.js +434 -0
- package/dist/figma-mcp-skills-parity.js.map +1 -0
- package/dist/figma-rest-diagnostics.d.ts +50 -0
- package/dist/figma-rest-diagnostics.js +314 -0
- package/dist/figma-rest-diagnostics.js.map +1 -0
- package/dist/figma-rest.d.ts +27 -0
- package/dist/figma-rest.js +116 -0
- package/dist/figma-rest.js.map +1 -0
- package/dist/http-api.d.ts +14 -2
- package/dist/http-api.js +323 -17
- package/dist/http-api.js.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-factory.d.ts +6 -1
- package/dist/mcp-factory.js +23 -4
- package/dist/mcp-factory.js.map +1 -1
- package/dist/mcp-runtime-probe.d.ts +22 -0
- package/dist/mcp-runtime-probe.js +777 -0
- package/dist/mcp-runtime-probe.js.map +1 -0
- package/dist/mcp-server.d.ts +2 -1
- package/dist/mcp-server.js +2 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/sxl-mcp-instructions.js +97 -25
- package/dist/sxl-mcp-instructions.js.map +1 -1
- package/dist/tools/audit.d.ts +22 -6
- package/dist/tools/audit.js +49 -7
- package/dist/tools/audit.js.map +1 -1
- package/dist/tools/capability-matrix.d.ts +22 -0
- package/dist/tools/capability-matrix.js +38 -0
- package/dist/tools/capability-matrix.js.map +1 -0
- package/dist/tools/catalogue-bootstrap.d.ts +1 -0
- package/dist/tools/catalogue-bootstrap.js +665 -30
- package/dist/tools/catalogue-bootstrap.js.map +1 -1
- package/dist/tools/code-connect-context.d.ts +3 -0
- package/dist/tools/code-connect-context.js +319 -0
- package/dist/tools/code-connect-context.js.map +1 -0
- package/dist/tools/code-connect-template.d.ts +3 -0
- package/dist/tools/code-connect-template.js +111 -0
- package/dist/tools/code-connect-template.js.map +1 -0
- package/dist/tools/composition.js +13 -28
- package/dist/tools/composition.js.map +1 -1
- package/dist/tools/compositions-orchestration.d.ts +14 -14
- package/dist/tools/compositions-orchestration.js +2 -2
- package/dist/tools/compositions-orchestration.js.map +1 -1
- package/dist/tools/data.js +839 -27
- package/dist/tools/data.js.map +1 -1
- package/dist/tools/design-context.d.ts +3 -0
- package/dist/tools/design-context.js +197 -0
- package/dist/tools/design-context.js.map +1 -0
- package/dist/tools/destructive-confirmation.d.ts +10 -0
- package/dist/tools/destructive-confirmation.js +22 -0
- package/dist/tools/destructive-confirmation.js.map +1 -0
- package/dist/tools/diagnostics.js +76 -51
- package/dist/tools/diagnostics.js.map +1 -1
- package/dist/tools/figma-mcp-design.d.ts +3 -0
- package/dist/tools/figma-mcp-design.js +377 -0
- package/dist/tools/figma-mcp-design.js.map +1 -0
- package/dist/tools/figma-nodes.js +57 -43
- package/dist/tools/figma-nodes.js.map +1 -1
- package/dist/tools/figma-rc-extended.js +23 -6
- package/dist/tools/figma-rc-extended.js.map +1 -1
- package/dist/tools/figma-rest.d.ts +39 -0
- package/dist/tools/figma-rest.js +279 -0
- package/dist/tools/figma-rest.js.map +1 -0
- package/dist/tools/git.js +11 -7
- package/dist/tools/git.js.map +1 -1
- package/dist/tools/large-data.d.ts +14 -0
- package/dist/tools/large-data.js +189 -0
- package/dist/tools/large-data.js.map +1 -0
- package/dist/tools/meta.d.ts +6 -1
- package/dist/tools/meta.js +89 -11
- package/dist/tools/meta.js.map +1 -1
- package/dist/tools/metadata.d.ts +3 -0
- package/dist/tools/metadata.js +140 -0
- package/dist/tools/metadata.js.map +1 -0
- package/dist/tools/mockup.d.ts +15 -156
- package/dist/tools/mockup.js +54 -121
- package/dist/tools/mockup.js.map +1 -1
- package/dist/tools/orchestration.js +73 -45
- package/dist/tools/orchestration.js.map +1 -1
- package/dist/tools/prompts.d.ts +3 -0
- package/dist/tools/prompts.js +219 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/registry.d.ts +19 -1
- package/dist/tools/registry.js +4 -4
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/resources.d.ts +19 -2
- package/dist/tools/resources.js +149 -5
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/schema-contracts.d.ts +4763 -0
- package/dist/tools/schema-contracts.js +814 -0
- package/dist/tools/schema-contracts.js.map +1 -0
- package/dist/tools/screenshot.d.ts +3 -0
- package/dist/tools/screenshot.js +144 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/shared.d.ts +11 -1
- package/dist/tools/shared.js +55 -2
- package/dist/tools/shared.js.map +1 -1
- package/dist/tools/styles-orchestration.d.ts +2 -2
- package/dist/tools/styles-orchestration.js +13 -5
- package/dist/tools/styles-orchestration.js.map +1 -1
- package/dist/tools/styles.js +22 -8
- package/dist/tools/styles.js.map +1 -1
- package/dist/tools/tokens.d.ts +31 -692
- package/dist/tools/tokens.js +175 -135
- package/dist/tools/tokens.js.map +1 -1
- package/dist/tools/variable-defs.d.ts +3 -0
- package/dist/tools/variable-defs.js +338 -0
- package/dist/tools/variable-defs.js.map +1 -0
- package/dist/tools/variables-orchestration.js +13 -5
- package/dist/tools/variables-orchestration.js.map +1 -1
- package/dist/tools/variables.js +18 -15
- package/dist/tools/variables.js.map +1 -1
- package/dist/types.d.ts +53 -0
- package/dist/ultimate-readiness-audit.d.ts +37 -0
- package/dist/ultimate-readiness-audit.js +431 -0
- package/dist/ultimate-readiness-audit.js.map +1 -0
- package/dist/workflow-planner.d.ts +57 -0
- package/dist/workflow-planner.js +464 -0
- package/dist/workflow-planner.js.map +1 -0
- package/dist/ws-server.js +16 -3
- package/dist/ws-server.js.map +1 -1
- package/package.json +18 -2
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildCodeConnectSuggestions, } from "./codeconnect-suggestions.js";
|
|
4
|
+
function clampIndex(value, fallback) {
|
|
5
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
6
|
+
return fallback;
|
|
7
|
+
return Math.max(0, Math.floor(value));
|
|
8
|
+
}
|
|
9
|
+
function escapeStringLiteral(value) {
|
|
10
|
+
return value
|
|
11
|
+
.replace(/\\/g, "\\\\")
|
|
12
|
+
.replace(/'/g, "\\'")
|
|
13
|
+
.replace(/\r/g, "\\r")
|
|
14
|
+
.replace(/\n/g, "\\n");
|
|
15
|
+
}
|
|
16
|
+
function escapeTemplateLiteral(value, preserveExpressions = false) {
|
|
17
|
+
const escaped = value
|
|
18
|
+
.replace(/\\/g, "\\\\")
|
|
19
|
+
.replace(/`/g, "\\`")
|
|
20
|
+
.replace(/\$\{/g, preserveExpressions ? "${" : "\\${");
|
|
21
|
+
return escaped;
|
|
22
|
+
}
|
|
23
|
+
function pascalCase(value) {
|
|
24
|
+
const parts = value
|
|
25
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
26
|
+
.split(/[^a-zA-Z0-9]+/g)
|
|
27
|
+
.filter(Boolean);
|
|
28
|
+
if (parts.length === 0)
|
|
29
|
+
return "Component";
|
|
30
|
+
return parts.map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join("");
|
|
31
|
+
}
|
|
32
|
+
function camelCase(value) {
|
|
33
|
+
const pascal = pascalCase(value);
|
|
34
|
+
return `${pascal.slice(0, 1).toLowerCase()}${pascal.slice(1)}` || "value";
|
|
35
|
+
}
|
|
36
|
+
function safeIdentifier(value, used) {
|
|
37
|
+
const base = camelCase(value).replace(/^[^a-zA-Z_$]+/, "") || "value";
|
|
38
|
+
let next = base;
|
|
39
|
+
let index = 2;
|
|
40
|
+
while (used.has(next)) {
|
|
41
|
+
next = `${base}${index}`;
|
|
42
|
+
index += 1;
|
|
43
|
+
}
|
|
44
|
+
used.add(next);
|
|
45
|
+
return next;
|
|
46
|
+
}
|
|
47
|
+
function safeTemplateId(value) {
|
|
48
|
+
const id = value
|
|
49
|
+
.normalize("NFKD")
|
|
50
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
51
|
+
.toLowerCase()
|
|
52
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
53
|
+
.replace(/^-+|-+$/g, "")
|
|
54
|
+
.slice(0, 80);
|
|
55
|
+
return id || "code-connect-template";
|
|
56
|
+
}
|
|
57
|
+
function fileNameFor(value) {
|
|
58
|
+
const base = pascalCase(value);
|
|
59
|
+
return `${base}.figma.ts`;
|
|
60
|
+
}
|
|
61
|
+
function selectSuggestion(args) {
|
|
62
|
+
const suggestions = buildCodeConnectSuggestions({
|
|
63
|
+
targets: args.targets,
|
|
64
|
+
componentNames: args.componentNames,
|
|
65
|
+
rootDir: args.rootDir,
|
|
66
|
+
repositoryUrl: args.repositoryUrl,
|
|
67
|
+
gitlabUrl: args.gitlabUrl,
|
|
68
|
+
documentationUrl: args.documentationUrl,
|
|
69
|
+
documentationDocsQuerySuffix: args.documentationDocsQuerySuffix,
|
|
70
|
+
documentationStoryPathTemplate: args.documentationStoryPathTemplate,
|
|
71
|
+
frameworks: args.frameworks,
|
|
72
|
+
maxSuggestionsPerTarget: args.maxSuggestionsPerTarget,
|
|
73
|
+
maxFiles: args.maxFiles,
|
|
74
|
+
maxFileBytes: args.maxFileBytes,
|
|
75
|
+
includeLowConfidence: args.includeLowConfidence,
|
|
76
|
+
});
|
|
77
|
+
const target = suggestions.targets[clampIndex(args.targetIndex, 0)];
|
|
78
|
+
const suggestion = target?.suggestions[clampIndex(args.suggestionIndex, 0)];
|
|
79
|
+
if (!target || !suggestion)
|
|
80
|
+
return null;
|
|
81
|
+
return { target, suggestion };
|
|
82
|
+
}
|
|
83
|
+
function firstFile(binding) {
|
|
84
|
+
return binding.files?.find((file) => file.componentName || file.filePath || file.importPath) ?? binding.files?.[0];
|
|
85
|
+
}
|
|
86
|
+
function componentNameFor(binding) {
|
|
87
|
+
return firstFile(binding)?.componentName?.trim() || pascalCase(binding.displayName);
|
|
88
|
+
}
|
|
89
|
+
function importPathFor(binding) {
|
|
90
|
+
return binding.importPath?.trim() || firstFile(binding)?.importPath?.trim() || null;
|
|
91
|
+
}
|
|
92
|
+
function sourceFilePathFor(binding) {
|
|
93
|
+
return firstFile(binding)?.filePath?.trim() || null;
|
|
94
|
+
}
|
|
95
|
+
function snippetFor(binding, componentName, includeAttrs, attrs) {
|
|
96
|
+
if (!includeAttrs) {
|
|
97
|
+
return binding.snippetTemplate?.trim() || firstFile(binding)?.snippetTemplate?.trim() || `<${componentName} />`;
|
|
98
|
+
}
|
|
99
|
+
if (attrs.length === 0)
|
|
100
|
+
return `<${componentName} />`;
|
|
101
|
+
return `<${componentName} ${attrs.join(" ")} />`;
|
|
102
|
+
}
|
|
103
|
+
function propertyKind(property) {
|
|
104
|
+
return property.kind.trim().toUpperCase();
|
|
105
|
+
}
|
|
106
|
+
function accessorFor(property, variableName) {
|
|
107
|
+
const name = escapeStringLiteral(property.name);
|
|
108
|
+
const kind = propertyKind(property);
|
|
109
|
+
if (kind === "TEXT")
|
|
110
|
+
return `const ${variableName} = instance.getString('${name}')`;
|
|
111
|
+
if (kind === "BOOLEAN")
|
|
112
|
+
return `const ${variableName} = instance.getBoolean('${name}')`;
|
|
113
|
+
if (kind === "VARIANT") {
|
|
114
|
+
const options = Array.isArray(property.options) ? property.options : [];
|
|
115
|
+
const mapLines = options.length > 0
|
|
116
|
+
? options.map((option) => ` '${escapeStringLiteral(option)}': '${escapeStringLiteral(option)}',`).join("\n")
|
|
117
|
+
: ` '${escapeStringLiteral(String(property.defaultValue ?? "Default"))}': '${escapeStringLiteral(String(property.defaultValue ?? "Default"))}',`;
|
|
118
|
+
return `const ${variableName} = instance.getEnum('${name}', {\n${mapLines}\n})`;
|
|
119
|
+
}
|
|
120
|
+
if (kind === "INSTANCE_SWAP")
|
|
121
|
+
return `const ${variableName} = instance.getInstanceSwap('${name}')`;
|
|
122
|
+
if (kind === "SLOT")
|
|
123
|
+
return `const ${variableName} = instance.getSlot('${name}')`;
|
|
124
|
+
return `const ${variableName} = instance.getString('${name}')`;
|
|
125
|
+
}
|
|
126
|
+
function propertyAttr(property, variableName) {
|
|
127
|
+
const propName = camelCase(property.name);
|
|
128
|
+
const kind = propertyKind(property);
|
|
129
|
+
if (kind === "TEXT" || kind === "VARIANT")
|
|
130
|
+
return `${propName}={\${${variableName}}}`;
|
|
131
|
+
if (kind === "BOOLEAN")
|
|
132
|
+
return `${propName}={\${${variableName}}}`;
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
function buildPropertyBlock(binding, includeAccessors, includeMetadata, includeAttrs) {
|
|
136
|
+
const properties = binding.storybook?.componentApi?.properties ?? [];
|
|
137
|
+
if (!includeAccessors || properties.length === 0) {
|
|
138
|
+
return { lines: [], metadataLines: [], attrs: [], names: [] };
|
|
139
|
+
}
|
|
140
|
+
const used = new Set();
|
|
141
|
+
const lines = [];
|
|
142
|
+
const metadataLines = [];
|
|
143
|
+
const attrs = [];
|
|
144
|
+
const names = [];
|
|
145
|
+
for (const property of properties) {
|
|
146
|
+
if (!property.name.trim())
|
|
147
|
+
continue;
|
|
148
|
+
const variableName = safeIdentifier(property.name, used);
|
|
149
|
+
names.push(variableName);
|
|
150
|
+
lines.push(accessorFor(property, variableName));
|
|
151
|
+
if (includeMetadata)
|
|
152
|
+
metadataLines.push(` ${variableName},`);
|
|
153
|
+
const attr = includeAttrs ? propertyAttr(property, variableName) : null;
|
|
154
|
+
if (attr)
|
|
155
|
+
attrs.push(attr);
|
|
156
|
+
}
|
|
157
|
+
return { lines, metadataLines, attrs, names };
|
|
158
|
+
}
|
|
159
|
+
function outputPathFor(args, binding, rootDir, componentName) {
|
|
160
|
+
if (args.outputPath?.trim())
|
|
161
|
+
return path.resolve(args.outputPath);
|
|
162
|
+
const fileName = args.fileName?.trim() || fileNameFor(componentName);
|
|
163
|
+
if (args.outputDir?.trim())
|
|
164
|
+
return path.resolve(rootDir, args.outputDir, fileName);
|
|
165
|
+
const sourceFile = sourceFilePathFor(binding);
|
|
166
|
+
const sourceDir = sourceFile ? path.dirname(sourceFile) : ".";
|
|
167
|
+
return path.resolve(rootDir, sourceDir, fileName);
|
|
168
|
+
}
|
|
169
|
+
function assertInsideRoot(outputPath, rootDir, allowOutsideRoot) {
|
|
170
|
+
if (allowOutsideRoot)
|
|
171
|
+
return;
|
|
172
|
+
const relative = path.relative(rootDir, outputPath);
|
|
173
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
174
|
+
throw new Error("outputPath must stay inside rootDir unless allowOutsideRoot=true");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function templateContent(args, binding) {
|
|
178
|
+
const componentName = componentNameFor(binding);
|
|
179
|
+
const importPath = importPathFor(binding);
|
|
180
|
+
const sourceFilePath = sourceFilePathFor(binding);
|
|
181
|
+
const includeAccessors = args.includePropertyAccessors !== false;
|
|
182
|
+
const includeMetadata = args.includePropertyMetadata !== false;
|
|
183
|
+
const includeAttrs = args.includePropertyAttrs === true;
|
|
184
|
+
const props = buildPropertyBlock(binding, includeAccessors, includeMetadata, includeAttrs);
|
|
185
|
+
const snippet = snippetFor(binding, componentName, includeAttrs, props.attrs);
|
|
186
|
+
const lines = [];
|
|
187
|
+
if (args.figmaUrl?.trim())
|
|
188
|
+
lines.push(`// url=${args.figmaUrl.trim()}`);
|
|
189
|
+
else if (args.nodeId?.trim())
|
|
190
|
+
lines.push(`// node-id=${args.nodeId.trim()}`);
|
|
191
|
+
if (sourceFilePath)
|
|
192
|
+
lines.push(`// source=${sourceFilePath}`);
|
|
193
|
+
lines.push(`// component=${componentName}`);
|
|
194
|
+
lines.push("import figma from 'figma'");
|
|
195
|
+
lines.push("");
|
|
196
|
+
lines.push("const instance = figma.selectedInstance");
|
|
197
|
+
if (props.lines.length > 0) {
|
|
198
|
+
lines.push("");
|
|
199
|
+
lines.push(...props.lines);
|
|
200
|
+
}
|
|
201
|
+
lines.push("");
|
|
202
|
+
lines.push("export default {");
|
|
203
|
+
lines.push(` id: '${safeTemplateId(binding.displayName || componentName)}',`);
|
|
204
|
+
lines.push(` example: figma.code\`${escapeTemplateLiteral(snippet, includeAttrs)}\`,`);
|
|
205
|
+
if (importPath) {
|
|
206
|
+
lines.push(` imports: ['import { ${componentName} } from "${escapeStringLiteral(importPath)}"'],`);
|
|
207
|
+
}
|
|
208
|
+
if (includeMetadata && props.metadataLines.length > 0) {
|
|
209
|
+
lines.push(" metadata: {");
|
|
210
|
+
lines.push(" nestable: true,");
|
|
211
|
+
lines.push(" props: {");
|
|
212
|
+
lines.push(...props.metadataLines);
|
|
213
|
+
lines.push(" },");
|
|
214
|
+
lines.push(" },");
|
|
215
|
+
}
|
|
216
|
+
lines.push("}");
|
|
217
|
+
lines.push("");
|
|
218
|
+
return {
|
|
219
|
+
content: lines.join("\n"),
|
|
220
|
+
componentName,
|
|
221
|
+
importPath,
|
|
222
|
+
sourceFilePath,
|
|
223
|
+
propertyAccessors: props.names,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
export function generateCodeConnectTemplate(args) {
|
|
227
|
+
const rootDir = path.resolve(args.rootDir ?? process.env.SXL_CODECONNECT_ROOT ?? process.cwd());
|
|
228
|
+
const selected = args.binding ? null : selectSuggestion(args);
|
|
229
|
+
const binding = (args.binding ?? selected?.suggestion.binding);
|
|
230
|
+
if (!binding) {
|
|
231
|
+
throw new Error("No Code Connect binding available. Provide binding or componentNames/targets with a matching local source file.");
|
|
232
|
+
}
|
|
233
|
+
const generated = templateContent(args, binding);
|
|
234
|
+
const outputPath = outputPathFor(args, binding, rootDir, generated.componentName);
|
|
235
|
+
assertInsideRoot(outputPath, rootDir, args.allowOutsideRoot);
|
|
236
|
+
const writeRequested = args.writeFile === true;
|
|
237
|
+
const existed = existsSync(outputPath);
|
|
238
|
+
if (writeRequested) {
|
|
239
|
+
if (existed && args.overwrite !== true) {
|
|
240
|
+
throw new Error(`Template already exists at ${outputPath}. Set overwrite=true to replace it.`);
|
|
241
|
+
}
|
|
242
|
+
mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
243
|
+
writeFileSync(outputPath, generated.content, "utf8");
|
|
244
|
+
}
|
|
245
|
+
const warnings = [];
|
|
246
|
+
if (generated.propertyAccessors.length > 0 && args.includePropertyAttrs !== true) {
|
|
247
|
+
warnings.push("Figma component API properties were emitted as accessors/metadata only. Set includePropertyAttrs=true only after verifying matching code component prop names.");
|
|
248
|
+
}
|
|
249
|
+
if (!generated.importPath) {
|
|
250
|
+
warnings.push("No importPath was available; imports[] was omitted from the generated template.");
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
ok: true,
|
|
254
|
+
source: "bridge-code-connect-template",
|
|
255
|
+
dryRun: !writeRequested,
|
|
256
|
+
generatedAt: new Date().toISOString(),
|
|
257
|
+
target: selected?.target ?? null,
|
|
258
|
+
binding,
|
|
259
|
+
template: {
|
|
260
|
+
fileName: path.basename(outputPath),
|
|
261
|
+
outputPath,
|
|
262
|
+
content: generated.content,
|
|
263
|
+
bytes: Buffer.byteLength(generated.content, "utf8"),
|
|
264
|
+
componentName: generated.componentName,
|
|
265
|
+
importPath: generated.importPath,
|
|
266
|
+
sourceFilePath: generated.sourceFilePath,
|
|
267
|
+
propertyAccessors: generated.propertyAccessors,
|
|
268
|
+
},
|
|
269
|
+
write: {
|
|
270
|
+
requested: writeRequested,
|
|
271
|
+
written: writeRequested,
|
|
272
|
+
overwritten: writeRequested && existed,
|
|
273
|
+
},
|
|
274
|
+
warnings,
|
|
275
|
+
nextStep: writeRequested
|
|
276
|
+
? "Review the generated .figma.ts template, adjust prop mappings if needed, then publish/apply Code Connect through your normal repository workflow."
|
|
277
|
+
: "Review template.content and call generate_code_connect_template with writeFile=true to create the .figma.ts file.",
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=codeconnect-template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codeconnect-template.js","sourceRoot":"","sources":["../src/codeconnect-template.ts"],"names":[],"mappings":"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"}
|
package/dist/command-queue.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Serial execution: one command at a time.
|
|
5
5
|
* Each command has a timeout. Results are resolved via promises.
|
|
6
6
|
*/
|
|
7
|
-
import type { CommandResult, CommandStatus } from "./types.js";
|
|
7
|
+
import type { CommandQueueSnapshot, CommandResult, CommandStatus, CommandTelemetryEvent, CommandTelemetrySummary } from "./types.js";
|
|
8
8
|
/** Per-command client timeouts. Keep long to avoid client-side aborts on heavy files. */
|
|
9
9
|
export declare const BRIDGE_COMMAND_TIMEOUT_MS: Readonly<Record<string, number>>;
|
|
10
10
|
type CommandSender = (command: {
|
|
@@ -18,9 +18,16 @@ export declare class CommandQueue {
|
|
|
18
18
|
private immediate;
|
|
19
19
|
private sendCommand;
|
|
20
20
|
private timeoutHandles;
|
|
21
|
+
private events;
|
|
21
22
|
setSender(sender: CommandSender): void;
|
|
22
23
|
get queueLength(): number;
|
|
23
24
|
get currentCommand(): string | null;
|
|
25
|
+
getSnapshot(now?: number): CommandQueueSnapshot;
|
|
26
|
+
getEventsSnapshot(filters?: {
|
|
27
|
+
limit?: number;
|
|
28
|
+
commandId?: string | null;
|
|
29
|
+
}): CommandTelemetryEvent[];
|
|
30
|
+
getTelemetrySummary(now?: number): CommandTelemetrySummary;
|
|
24
31
|
execute(commandType: string, payload?: Record<string, unknown>): Promise<CommandResult>;
|
|
25
32
|
/**
|
|
26
33
|
* Out-of-band command dispatch for control-plane operations.
|
|
@@ -35,7 +42,10 @@ export declare class CommandQueue {
|
|
|
35
42
|
resolveCommand(commandId: string, status: CommandStatus, result?: unknown, error?: string, events?: unknown[], durationMs?: number): void;
|
|
36
43
|
cancelAll(): void;
|
|
37
44
|
private processNext;
|
|
45
|
+
recordPluginEvent(raw: unknown): void;
|
|
38
46
|
private clearTimeout;
|
|
39
47
|
private clearAllTimeouts;
|
|
48
|
+
private recordCommandEvent;
|
|
49
|
+
private recordTelemetryEvent;
|
|
40
50
|
}
|
|
41
51
|
export {};
|
package/dist/command-queue.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Each command has a timeout. Results are resolved via promises.
|
|
6
6
|
*/
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { guardDestructiveCommand } from "./command-safety.js";
|
|
8
9
|
/** Per-command client timeouts. Keep long to avoid client-side aborts on heavy files. */
|
|
9
10
|
export const BRIDGE_COMMAND_TIMEOUT_MS = {
|
|
10
11
|
export_variables: 3_600_000,
|
|
@@ -16,6 +17,21 @@ export const BRIDGE_COMMAND_TIMEOUT_MS = {
|
|
|
16
17
|
apply_all_mappings: 3_600_000,
|
|
17
18
|
export_composition_json: 3_600_000,
|
|
18
19
|
get_token_file_content: 3_600_000,
|
|
20
|
+
list_datasets: 3_600_000,
|
|
21
|
+
get_dataset: 3_600_000,
|
|
22
|
+
save_dataset: 3_600_000,
|
|
23
|
+
delete_dataset: 3_600_000,
|
|
24
|
+
list_assets: 3_600_000,
|
|
25
|
+
get_asset: 3_600_000,
|
|
26
|
+
save_asset: 3_600_000,
|
|
27
|
+
delete_asset: 3_600_000,
|
|
28
|
+
list_mappings: 3_600_000,
|
|
29
|
+
get_mapping: 3_600_000,
|
|
30
|
+
save_mapping: 3_600_000,
|
|
31
|
+
delete_mapping: 3_600_000,
|
|
32
|
+
inspect_enabled_libraries: 3_600_000,
|
|
33
|
+
list_enabled_library_variables: 3_600_000,
|
|
34
|
+
search_enabled_library_assets: 3_600_000,
|
|
19
35
|
save_token_file: 3_600_000,
|
|
20
36
|
duplicate_subtree: 3_600_000,
|
|
21
37
|
apply_documentation_payload: 3_600_000,
|
|
@@ -41,6 +57,10 @@ export const BRIDGE_COMMAND_TIMEOUT_MS = {
|
|
|
41
57
|
flatten_nodes: 3_600_000,
|
|
42
58
|
get_local_styles: 3_600_000,
|
|
43
59
|
list_components: 3_600_000,
|
|
60
|
+
get_metadata: 3_600_000,
|
|
61
|
+
get_design_context: 3_600_000,
|
|
62
|
+
get_context_for_code_connect: 3_600_000,
|
|
63
|
+
generate_code_connect_template: 3_600_000,
|
|
44
64
|
find_nodes: 3_600_000,
|
|
45
65
|
get_page_structure: 3_600_000,
|
|
46
66
|
get_variables: 3_600_000,
|
|
@@ -55,6 +75,12 @@ export const BRIDGE_COMMAND_TIMEOUT_MS = {
|
|
|
55
75
|
find_style_coverage_misses: 3_600_000,
|
|
56
76
|
find_unused_variables: 3_600_000,
|
|
57
77
|
find_unused_styles: 3_600_000,
|
|
78
|
+
analyze_component_usage: 3_600_000,
|
|
79
|
+
find_component_usages: 3_600_000,
|
|
80
|
+
analyze_component_prop_usage: 3_600_000,
|
|
81
|
+
find_component_prop_usages: 3_600_000,
|
|
82
|
+
get_selection_variable_defs: 3_600_000,
|
|
83
|
+
update_screen: 3_600_000,
|
|
58
84
|
/** Variables orchestration (Bridge platform Phase B) */
|
|
59
85
|
import_variable_spec: 3_600_000,
|
|
60
86
|
analyze_variable_order: 3_600_000,
|
|
@@ -63,6 +89,7 @@ export const BRIDGE_COMMAND_TIMEOUT_MS = {
|
|
|
63
89
|
apply_coverage_suggestions: 3_600_000,
|
|
64
90
|
};
|
|
65
91
|
const DEFAULT_TIMEOUT = 3_600_000;
|
|
92
|
+
const EVENT_BUFFER_SIZE = 1_000;
|
|
66
93
|
const IMMEDIATE_COMMAND_TYPES = new Set([
|
|
67
94
|
"cancel_composition_generation",
|
|
68
95
|
]);
|
|
@@ -72,6 +99,7 @@ export class CommandQueue {
|
|
|
72
99
|
immediate = new Map();
|
|
73
100
|
sendCommand = null;
|
|
74
101
|
timeoutHandles = new Map();
|
|
102
|
+
events = [];
|
|
75
103
|
setSender(sender) {
|
|
76
104
|
this.sendCommand = sender;
|
|
77
105
|
}
|
|
@@ -81,11 +109,60 @@ export class CommandQueue {
|
|
|
81
109
|
get currentCommand() {
|
|
82
110
|
return this.current?.commandType ?? null;
|
|
83
111
|
}
|
|
112
|
+
getSnapshot(now = Date.now()) {
|
|
113
|
+
return {
|
|
114
|
+
current: this.current ? snapshotCommand(this.current, now) : null,
|
|
115
|
+
queued: this.queue.map((command) => snapshotCommand(command, now)),
|
|
116
|
+
immediate: Array.from(this.immediate.values()).map((command) => snapshotCommand(command, now)),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
getEventsSnapshot(filters = {}) {
|
|
120
|
+
const limit = Math.max(1, Math.min(filters.limit ?? 100, EVENT_BUFFER_SIZE));
|
|
121
|
+
let source = this.events;
|
|
122
|
+
if (filters.commandId) {
|
|
123
|
+
source = source.filter((event) => event.commandId === filters.commandId);
|
|
124
|
+
}
|
|
125
|
+
return source.slice(-limit).reverse();
|
|
126
|
+
}
|
|
127
|
+
getTelemetrySummary(now = Date.now()) {
|
|
128
|
+
const failures = this.events.filter((event) => event.status === "failed" || event.status === "timeout");
|
|
129
|
+
const lastEvent = this.events.at(-1);
|
|
130
|
+
const lastFailure = failures.at(-1);
|
|
131
|
+
return {
|
|
132
|
+
eventsBuffered: this.events.length,
|
|
133
|
+
bridgeEventsBuffered: this.events.filter((event) => event.source === "bridge").length,
|
|
134
|
+
pluginEventsBuffered: this.events.filter((event) => event.source === "plugin").length,
|
|
135
|
+
failuresBuffered: failures.filter((event) => event.status === "failed").length,
|
|
136
|
+
timeoutsBuffered: failures.filter((event) => event.status === "timeout").length,
|
|
137
|
+
lastEventAt: lastEvent?.at ?? null,
|
|
138
|
+
lastEventAgeMs: lastEvent ? Math.max(0, now - lastEvent.at) : null,
|
|
139
|
+
lastFailureAt: lastFailure?.at ?? null,
|
|
140
|
+
lastFailureAgeMs: lastFailure ? Math.max(0, now - lastFailure.at) : null,
|
|
141
|
+
lastFailureCommandType: lastFailure?.commandType ?? null,
|
|
142
|
+
lastFailureMessage: lastFailure?.message ?? null,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
84
145
|
async execute(commandType, payload = {}) {
|
|
146
|
+
const commandId = randomUUID();
|
|
147
|
+
const safety = guardDestructiveCommand(commandType, payload);
|
|
148
|
+
if (!safety.ok) {
|
|
149
|
+
this.recordTelemetryEvent({
|
|
150
|
+
source: "bridge",
|
|
151
|
+
phase: "failed",
|
|
152
|
+
commandId,
|
|
153
|
+
commandType,
|
|
154
|
+
status: "failed",
|
|
155
|
+
durationMs: 0,
|
|
156
|
+
message: safety.error,
|
|
157
|
+
payloadKeys: Object.keys(payload ?? {}),
|
|
158
|
+
detailKeys: ["safety"],
|
|
159
|
+
});
|
|
160
|
+
return { commandId, status: "failed", error: safety.error };
|
|
161
|
+
}
|
|
162
|
+
payload = safety.payload;
|
|
85
163
|
if (IMMEDIATE_COMMAND_TYPES.has(commandType)) {
|
|
86
164
|
return this.executeImmediate(commandType, payload);
|
|
87
165
|
}
|
|
88
|
-
const commandId = randomUUID();
|
|
89
166
|
const timeout = BRIDGE_COMMAND_TIMEOUT_MS[commandType] ?? DEFAULT_TIMEOUT;
|
|
90
167
|
return new Promise((resolve) => {
|
|
91
168
|
const command = {
|
|
@@ -97,6 +174,7 @@ export class CommandQueue {
|
|
|
97
174
|
resolve,
|
|
98
175
|
};
|
|
99
176
|
this.queue.push(command);
|
|
177
|
+
this.recordCommandEvent(command, "queued");
|
|
100
178
|
this.processNext();
|
|
101
179
|
this.scheduleTimeout(command, timeout);
|
|
102
180
|
});
|
|
@@ -111,6 +189,22 @@ export class CommandQueue {
|
|
|
111
189
|
*/
|
|
112
190
|
async executeImmediate(commandType, payload) {
|
|
113
191
|
const commandId = randomUUID();
|
|
192
|
+
const safety = guardDestructiveCommand(commandType, payload);
|
|
193
|
+
if (!safety.ok) {
|
|
194
|
+
this.recordTelemetryEvent({
|
|
195
|
+
source: "bridge",
|
|
196
|
+
phase: "failed",
|
|
197
|
+
commandId,
|
|
198
|
+
commandType,
|
|
199
|
+
status: "failed",
|
|
200
|
+
durationMs: 0,
|
|
201
|
+
message: safety.error,
|
|
202
|
+
payloadKeys: Object.keys(payload ?? {}),
|
|
203
|
+
detailKeys: ["safety"],
|
|
204
|
+
});
|
|
205
|
+
return { commandId, status: "failed", error: safety.error };
|
|
206
|
+
}
|
|
207
|
+
payload = safety.payload;
|
|
114
208
|
const timeout = BRIDGE_COMMAND_TIMEOUT_MS[commandType] ?? DEFAULT_TIMEOUT;
|
|
115
209
|
return new Promise((resolve) => {
|
|
116
210
|
const command = {
|
|
@@ -122,9 +216,11 @@ export class CommandQueue {
|
|
|
122
216
|
startedAt: Date.now(),
|
|
123
217
|
resolve,
|
|
124
218
|
};
|
|
219
|
+
this.recordCommandEvent(command, "started");
|
|
125
220
|
if (!this.sendCommand) {
|
|
126
221
|
command.status = "failed";
|
|
127
222
|
command.completedAt = Date.now();
|
|
223
|
+
this.recordCommandEvent(command, "failed", { message: "No plugin connected" });
|
|
128
224
|
resolve({ commandId, status: "failed", error: "No plugin connected" });
|
|
129
225
|
return;
|
|
130
226
|
}
|
|
@@ -136,6 +232,7 @@ export class CommandQueue {
|
|
|
136
232
|
if (!sent) {
|
|
137
233
|
command.status = "failed";
|
|
138
234
|
command.completedAt = Date.now();
|
|
235
|
+
this.recordCommandEvent(command, "failed", { message: "Failed to send to plugin" });
|
|
139
236
|
resolve({ commandId, status: "failed", error: "Failed to send to plugin" });
|
|
140
237
|
return;
|
|
141
238
|
}
|
|
@@ -149,6 +246,7 @@ export class CommandQueue {
|
|
|
149
246
|
command.status = "timeout";
|
|
150
247
|
command.completedAt = Date.now();
|
|
151
248
|
command.error = `Command "${command.commandType}" timed out after ${timeout}ms`;
|
|
249
|
+
this.recordCommandEvent(command, "timeout", { message: command.error });
|
|
152
250
|
command.resolve?.({
|
|
153
251
|
commandId: command.commandId,
|
|
154
252
|
status: "timeout",
|
|
@@ -176,6 +274,7 @@ export class CommandQueue {
|
|
|
176
274
|
target.error = error;
|
|
177
275
|
target.events = events;
|
|
178
276
|
target.durationMs = durationMs;
|
|
277
|
+
this.recordCommandEvent(target, status, { message: error, detailKeys: eventDetailKeys(events) });
|
|
179
278
|
target.resolve?.({
|
|
180
279
|
commandId,
|
|
181
280
|
status,
|
|
@@ -197,6 +296,8 @@ export class CommandQueue {
|
|
|
197
296
|
for (const cmd of this.queue) {
|
|
198
297
|
if (cmd.status === "pending") {
|
|
199
298
|
cmd.status = "cancelled";
|
|
299
|
+
cmd.completedAt = Date.now();
|
|
300
|
+
this.recordCommandEvent(cmd, "cancelled", { message: "Session disconnected" });
|
|
200
301
|
cmd.resolve?.({ commandId: cmd.commandId, status: "cancelled", error: "Session disconnected" });
|
|
201
302
|
}
|
|
202
303
|
}
|
|
@@ -204,12 +305,16 @@ export class CommandQueue {
|
|
|
204
305
|
for (const cmd of this.immediate.values()) {
|
|
205
306
|
if (cmd.status === "pending" || cmd.status === "running") {
|
|
206
307
|
cmd.status = "cancelled";
|
|
308
|
+
cmd.completedAt = Date.now();
|
|
309
|
+
this.recordCommandEvent(cmd, "cancelled", { message: "Session disconnected" });
|
|
207
310
|
cmd.resolve?.({ commandId: cmd.commandId, status: "cancelled", error: "Session disconnected" });
|
|
208
311
|
}
|
|
209
312
|
}
|
|
210
313
|
this.immediate.clear();
|
|
211
314
|
if (this.current && this.current.status === "running") {
|
|
212
315
|
this.current.status = "cancelled";
|
|
316
|
+
this.current.completedAt = Date.now();
|
|
317
|
+
this.recordCommandEvent(this.current, "cancelled", { message: "Session disconnected" });
|
|
213
318
|
this.current.resolve?.({ commandId: this.current.commandId, status: "cancelled", error: "Session disconnected" });
|
|
214
319
|
this.current = null;
|
|
215
320
|
}
|
|
@@ -229,6 +334,8 @@ export class CommandQueue {
|
|
|
229
334
|
}
|
|
230
335
|
if (!this.sendCommand) {
|
|
231
336
|
next.status = "failed";
|
|
337
|
+
next.completedAt = Date.now();
|
|
338
|
+
this.recordCommandEvent(next, "failed", { message: "No plugin connected" });
|
|
232
339
|
next.resolve?.({ commandId: next.commandId, status: "failed", error: "No plugin connected" });
|
|
233
340
|
this.processNext();
|
|
234
341
|
return;
|
|
@@ -240,6 +347,8 @@ export class CommandQueue {
|
|
|
240
347
|
});
|
|
241
348
|
if (!sent) {
|
|
242
349
|
next.status = "failed";
|
|
350
|
+
next.completedAt = Date.now();
|
|
351
|
+
this.recordCommandEvent(next, "failed", { message: "Failed to send to plugin" });
|
|
243
352
|
next.resolve?.({ commandId: next.commandId, status: "failed", error: "Failed to send to plugin" });
|
|
244
353
|
this.processNext();
|
|
245
354
|
return;
|
|
@@ -247,6 +356,40 @@ export class CommandQueue {
|
|
|
247
356
|
next.status = "running";
|
|
248
357
|
next.startedAt = Date.now();
|
|
249
358
|
this.current = next;
|
|
359
|
+
this.recordCommandEvent(next, "started");
|
|
360
|
+
}
|
|
361
|
+
recordPluginEvent(raw) {
|
|
362
|
+
if (!raw || typeof raw !== "object") {
|
|
363
|
+
this.recordTelemetryEvent({
|
|
364
|
+
source: "plugin",
|
|
365
|
+
phase: "plugin-event",
|
|
366
|
+
commandId: null,
|
|
367
|
+
commandType: null,
|
|
368
|
+
status: null,
|
|
369
|
+
durationMs: null,
|
|
370
|
+
message: typeof raw === "string" ? raw : null,
|
|
371
|
+
payloadKeys: [],
|
|
372
|
+
detailKeys: [],
|
|
373
|
+
});
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const envelope = raw;
|
|
377
|
+
const event = isRecord(envelope.event) ? envelope.event : envelope;
|
|
378
|
+
this.recordTelemetryEvent({
|
|
379
|
+
source: "plugin",
|
|
380
|
+
phase: typeof event.phase === "string"
|
|
381
|
+
? event.phase
|
|
382
|
+
: typeof event.type === "string"
|
|
383
|
+
? event.type
|
|
384
|
+
: "plugin-event",
|
|
385
|
+
commandId: typeof event.commandId === "string" ? event.commandId : null,
|
|
386
|
+
commandType: typeof event.commandType === "string" ? event.commandType : null,
|
|
387
|
+
status: isCommandStatus(event.status) ? event.status : null,
|
|
388
|
+
durationMs: typeof event.durationMs === "number" ? event.durationMs : null,
|
|
389
|
+
message: typeof event.message === "string" ? event.message : null,
|
|
390
|
+
payloadKeys: [],
|
|
391
|
+
detailKeys: Object.keys(event).filter((key) => !["commandId", "commandType", "phase", "type", "status", "durationMs", "message"].includes(key)),
|
|
392
|
+
});
|
|
250
393
|
}
|
|
251
394
|
clearTimeout(commandId) {
|
|
252
395
|
const handle = this.timeoutHandles.get(commandId);
|
|
@@ -261,5 +404,61 @@ export class CommandQueue {
|
|
|
261
404
|
}
|
|
262
405
|
this.timeoutHandles.clear();
|
|
263
406
|
}
|
|
407
|
+
recordCommandEvent(command, phase, extras = {}) {
|
|
408
|
+
this.recordTelemetryEvent({
|
|
409
|
+
source: "bridge",
|
|
410
|
+
phase,
|
|
411
|
+
commandId: command.commandId,
|
|
412
|
+
commandType: command.commandType,
|
|
413
|
+
status: command.status,
|
|
414
|
+
durationMs: command.durationMs ?? (command.startedAt && command.completedAt ? command.completedAt - command.startedAt : null),
|
|
415
|
+
message: extras.message ?? command.error ?? null,
|
|
416
|
+
payloadKeys: Object.keys(command.payload ?? {}),
|
|
417
|
+
detailKeys: extras.detailKeys ?? [],
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
recordTelemetryEvent(event) {
|
|
421
|
+
this.events.push({
|
|
422
|
+
eventId: randomUUID(),
|
|
423
|
+
at: Date.now(),
|
|
424
|
+
...event,
|
|
425
|
+
});
|
|
426
|
+
if (this.events.length > EVENT_BUFFER_SIZE) {
|
|
427
|
+
this.events.splice(0, this.events.length - EVENT_BUFFER_SIZE);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
function snapshotCommand(command, now) {
|
|
432
|
+
return {
|
|
433
|
+
commandId: command.commandId,
|
|
434
|
+
commandType: command.commandType,
|
|
435
|
+
status: command.status,
|
|
436
|
+
createdAt: command.createdAt,
|
|
437
|
+
startedAt: command.startedAt ?? null,
|
|
438
|
+
completedAt: command.completedAt ?? null,
|
|
439
|
+
ageMs: Math.max(0, now - command.createdAt),
|
|
440
|
+
runningMs: command.startedAt ? Math.max(0, now - command.startedAt) : null,
|
|
441
|
+
payloadKeys: Object.keys(command.payload ?? {}),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function eventDetailKeys(events) {
|
|
445
|
+
if (!events || events.length === 0)
|
|
446
|
+
return [];
|
|
447
|
+
return events.flatMap((event, index) => {
|
|
448
|
+
if (!event || typeof event !== "object")
|
|
449
|
+
return [`events[${index}]`];
|
|
450
|
+
return Object.keys(event).map((key) => `events[${index}].${key}`);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
function isRecord(value) {
|
|
454
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
455
|
+
}
|
|
456
|
+
function isCommandStatus(value) {
|
|
457
|
+
return (value === "pending" ||
|
|
458
|
+
value === "running" ||
|
|
459
|
+
value === "completed" ||
|
|
460
|
+
value === "failed" ||
|
|
461
|
+
value === "timeout" ||
|
|
462
|
+
value === "cancelled");
|
|
264
463
|
}
|
|
265
464
|
//# sourceMappingURL=command-queue.js.map
|