@tendrilapp/cli 0.1.30 → 0.1.31
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/dist/SKILL.md +6 -1
- package/dist/tendril-mcp.js +7 -2
- package/dist/tendril.js +50 -7
- package/package.json +1 -1
package/dist/SKILL.md
CHANGED
|
@@ -131,7 +131,12 @@ Batch runs (several components in one session):
|
|
|
131
131
|
2. `tendril_record_plan` with the response text passed VERBATIM via
|
|
132
132
|
`metadataParts` (one array entry per response block, in order —
|
|
133
133
|
single-block responses may use `metadata` instead; nothing is saved
|
|
134
|
-
to a file, and never hand-join blocks)
|
|
134
|
+
to a file, and never hand-join blocks), AND `figmaFile` set to the
|
|
135
|
+
file key from the URL you were handed (figma.com/design/<KEY>/… —
|
|
136
|
+
pass exactly KEY): it is recorded as the set's file identity for
|
|
137
|
+
cross-bundle composition, captured at plan time only and never
|
|
138
|
+
backfillable — a set planned without it can never join across
|
|
139
|
+
bundles → the queue plan. The plan
|
|
135
140
|
records the FULL variant matrix — every pose the set defines
|
|
136
141
|
(sampling exists only as a human-run CLI flag; the MCP surface
|
|
137
142
|
cannot sample). CROSS-CHECK `variantsFound` in the plan output
|
package/dist/tendril-mcp.js
CHANGED
|
@@ -37,7 +37,8 @@ var TOOLS = [
|
|
|
37
37
|
metadata: optStr("ONLY when get_metadata genuinely returned one single block: its text verbatim (otherwise use metadataParts)"),
|
|
38
38
|
metadataFiles: z.array(z.string()).optional().describe('saved verbatim get_metadata envelope file paths \u2014 JSON shape {"content":[{"type":"text","text":"<frame \u2026>"}]}; optionally <file>@<frameId>. Prefer metadataParts: no file to write'),
|
|
39
39
|
defaults: z.array(z.string()).optional().describe(`axis defaults as "Axis=Value" (from the user's defaultsToConfirm answers; may re-plan a set with nothing recorded yet)`),
|
|
40
|
-
componentSet: optStr("record only this component set (the user's pick from a multiple-component-sets error)")
|
|
40
|
+
componentSet: optStr("record only this component set (the user's pick from a multiple-component-sets error)"),
|
|
41
|
+
figmaFile: optStr("the Figma file key from the design URL you were handed \u2014 figma.com/design/<KEY>/\u2026, pass exactly <KEY>. ALWAYS pass it on a fresh plan: it is the set's recorded file identity for cross-bundle composition (ADR-013), captured at plan time only and never backfillable later")
|
|
41
42
|
}),
|
|
42
43
|
// Texts ride temp files, never argv: Windows caps a command line at
|
|
43
44
|
// ~32 KB and metadata envelopes can exceed it.
|
|
@@ -60,7 +61,11 @@ var TOOLS = [
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
if (argvOut.length === 6) throw new Error("nothing to plan from \u2014 pass metadataParts (normal), metadata (single-block), or metadataFiles");
|
|
63
|
-
argvOut.push(
|
|
64
|
+
argvOut.push(
|
|
65
|
+
...i["defaults"] !== void 0 ? ["--default", ...i["defaults"]] : [],
|
|
66
|
+
...i["componentSet"] !== void 0 ? ["--component-set", i["componentSet"]] : [],
|
|
67
|
+
...typeof i["figmaFile"] === "string" ? ["--figma-file", i["figmaFile"]] : []
|
|
68
|
+
);
|
|
64
69
|
return argvOut;
|
|
65
70
|
}
|
|
66
71
|
},
|
package/dist/tendril.js
CHANGED
|
@@ -1069,6 +1069,9 @@ function planSet(setDir, component, symbols, opts = {}) {
|
|
|
1069
1069
|
const manifest = {
|
|
1070
1070
|
version: 1,
|
|
1071
1071
|
component,
|
|
1072
|
+
...opts.figmaFile !== void 0 ? { figmaFile: opts.figmaFile } : {},
|
|
1073
|
+
...opts.componentSetNode !== void 0 ? { componentSetNode: opts.componentSetNode } : {},
|
|
1074
|
+
...opts.figmaComponentName !== void 0 ? { figmaComponentName: opts.figmaComponentName } : {},
|
|
1072
1075
|
...opts.sourceFrames !== void 0 ? { sourceFrames: opts.sourceFrames } : {},
|
|
1073
1076
|
...opts.variantScope !== void 0 ? { variantScope: opts.variantScope } : {},
|
|
1074
1077
|
...opts.defaults !== void 0 && Object.keys(opts.defaults).length > 0 ? { defaults: opts.defaults } : {},
|
|
@@ -1215,8 +1218,27 @@ var init_session = __esm({
|
|
|
1215
1218
|
SessionManifestSchema = z4.object({
|
|
1216
1219
|
version: z4.literal(1),
|
|
1217
1220
|
component: z4.string().min(1),
|
|
1221
|
+
/** ADR-013 slice 1 (v4, capture-only): cross-set identity, captured
|
|
1222
|
+
* at RECORD TIME on fresh plans only — NEVER backfilled (the
|
|
1223
|
+
* recording-set hash covers this file's bytes, so adding fields to
|
|
1224
|
+
* a set that already produced bundles voids their provenance).
|
|
1225
|
+
* `figmaFile` is the Figma file key from the URL the agent host was
|
|
1226
|
+
* handed — an AGENT ASSERTION, disclosed, never enforcement-bearing
|
|
1227
|
+
* alone (ADR-013 §1). `componentSetNode`/`figmaComponentName` are
|
|
1228
|
+
* the enclosing set's id and Figma-side name as the planner's own
|
|
1229
|
+
* metadata parse saw them — the identity that stops a re-recording
|
|
1230
|
+
* of the same component from reading as a different one (`component`
|
|
1231
|
+
* below is the plan-time DISPLAY name; the measured case recorded
|
|
1232
|
+
* one control as "Lucent Control (Dark)" and "control"). All
|
|
1233
|
+
* optional: legacy sets simply cannot join, disclosed. */
|
|
1234
|
+
figmaFile: z4.string().regex(/^[A-Za-z0-9]{8,64}$/).optional(),
|
|
1235
|
+
componentSetNode: z4.string().optional(),
|
|
1236
|
+
figmaComponentName: z4.string().optional(),
|
|
1218
1237
|
sourceFrames: z4.record(z4.string(), z4.string()).optional(),
|
|
1219
|
-
|
|
1238
|
+
/** Per-rep `componentKey` is SEEDED (ADR-013 v4: the one-call MCP
|
|
1239
|
+
* probe decides whether anything can ever fill it) so interim sets
|
|
1240
|
+
* are not born cross-file-dead if keys turn out to be available. */
|
|
1241
|
+
reps: z4.array(z4.object({ slug: z4.string(), nodeId: z4.string(), sourceFrame: z4.string().optional(), componentKey: z4.string().optional() })).min(1),
|
|
1220
1242
|
notRecorded: z4.string().optional(),
|
|
1221
1243
|
/** Explicit axis-default overrides from `record plan --default`.
|
|
1222
1244
|
* Recorded-truth-side on purpose: the default decides which pose an
|
|
@@ -7873,10 +7895,10 @@ function symbolsFromMetadataEnvelope(file, sourceFrame) {
|
|
|
7873
7895
|
nodeId: node.id,
|
|
7874
7896
|
name: node.name,
|
|
7875
7897
|
...sourceFrame !== void 0 ? { sourceFrame } : {},
|
|
7876
|
-
...ancestor !== void 0 ? { setName: ancestor } : {}
|
|
7898
|
+
...ancestor !== void 0 ? { setName: ancestor.name, setNodeId: ancestor.id } : {}
|
|
7877
7899
|
});
|
|
7878
7900
|
}
|
|
7879
|
-
const next = node.type !== "COMPONENT" && node.name !== "" ? node.name : ancestor;
|
|
7901
|
+
const next = node.type !== "COMPONENT" && node.name !== "" ? { name: node.name, id: node.id } : ancestor;
|
|
7880
7902
|
for (const child of node.children) walk2(child, next);
|
|
7881
7903
|
};
|
|
7882
7904
|
const forest = parseMetadataForest(text);
|
|
@@ -8014,10 +8036,25 @@ function runRecordPlan(opts) {
|
|
|
8014
8036
|
if (metadataTruncated) {
|
|
8015
8037
|
warn(opts, "get_metadata response appears TRUNCATED (unclosed structure) \u2014 the variant list below may be incomplete. Cross-check variantsFound against the variant count Figma shows for this component set; re-fetch the metadata if lower.");
|
|
8016
8038
|
}
|
|
8039
|
+
if (opts.figmaFile !== void 0 && !/^[A-Za-z0-9]{8,64}$/.test(opts.figmaFile)) {
|
|
8040
|
+
fail(opts, ExitCode.InputValidation, {
|
|
8041
|
+
error: `--figma-file must be the bare file key from the Figma URL (letters and digits only) \u2014 got ${JSON.stringify(opts.figmaFile)}`,
|
|
8042
|
+
code: "bad-figma-file",
|
|
8043
|
+
remediation: "From https://www.figma.com/design/<KEY>/<name>?node-id=\u2026, pass exactly <KEY>."
|
|
8044
|
+
});
|
|
8045
|
+
}
|
|
8046
|
+
const setIdentity = (() => {
|
|
8047
|
+
if (variantScope !== "component-set") return {};
|
|
8048
|
+
const ids = [...new Set(symbols.map((s) => s.setNodeId).filter((x) => x !== void 0))];
|
|
8049
|
+
const names = [...new Set(symbols.map((s) => s.setName).filter((x) => x !== void 0))];
|
|
8050
|
+
return ids.length === 1 && names.length === 1 ? { componentSetNode: ids[0], figmaComponentName: names[0] } : {};
|
|
8051
|
+
})();
|
|
8017
8052
|
const { manifest, plan, resumed, toppedUp } = planSet(opts.setDir, opts.component, symbols, {
|
|
8018
8053
|
...Object.keys(defaults).length > 0 ? { defaults } : {},
|
|
8019
8054
|
...opts.sample === true ? { sample: true } : {},
|
|
8020
|
-
variantScope
|
|
8055
|
+
variantScope,
|
|
8056
|
+
...opts.figmaFile !== void 0 ? { figmaFile: opts.figmaFile } : {},
|
|
8057
|
+
...setIdentity
|
|
8021
8058
|
});
|
|
8022
8059
|
const defaultReports = reportAxisDefaults(symbols, Object.keys(defaults).length > 0 ? defaults : void 0);
|
|
8023
8060
|
const toConfirm = resumed ? [] : defaultReports.filter((r) => (r.rule === "non-interaction" || r.rule === "frequency") && r.domain.length > 1);
|
|
@@ -12230,7 +12267,8 @@ var init_server = __esm({
|
|
|
12230
12267
|
metadata: optStr("ONLY when get_metadata genuinely returned one single block: its text verbatim (otherwise use metadataParts)"),
|
|
12231
12268
|
metadataFiles: z12.array(z12.string()).optional().describe('saved verbatim get_metadata envelope file paths \u2014 JSON shape {"content":[{"type":"text","text":"<frame \u2026>"}]}; optionally <file>@<frameId>. Prefer metadataParts: no file to write'),
|
|
12232
12269
|
defaults: z12.array(z12.string()).optional().describe(`axis defaults as "Axis=Value" (from the user's defaultsToConfirm answers; may re-plan a set with nothing recorded yet)`),
|
|
12233
|
-
componentSet: optStr("record only this component set (the user's pick from a multiple-component-sets error)")
|
|
12270
|
+
componentSet: optStr("record only this component set (the user's pick from a multiple-component-sets error)"),
|
|
12271
|
+
figmaFile: optStr("the Figma file key from the design URL you were handed \u2014 figma.com/design/<KEY>/\u2026, pass exactly <KEY>. ALWAYS pass it on a fresh plan: it is the set's recorded file identity for cross-bundle composition (ADR-013), captured at plan time only and never backfillable later")
|
|
12234
12272
|
}),
|
|
12235
12273
|
// Texts ride temp files, never argv: Windows caps a command line at
|
|
12236
12274
|
// ~32 KB and metadata envelopes can exceed it.
|
|
@@ -12253,7 +12291,11 @@ var init_server = __esm({
|
|
|
12253
12291
|
}
|
|
12254
12292
|
}
|
|
12255
12293
|
if (argvOut.length === 6) throw new Error("nothing to plan from \u2014 pass metadataParts (normal), metadata (single-block), or metadataFiles");
|
|
12256
|
-
argvOut.push(
|
|
12294
|
+
argvOut.push(
|
|
12295
|
+
...i["defaults"] !== void 0 ? ["--default", ...i["defaults"]] : [],
|
|
12296
|
+
...i["componentSet"] !== void 0 ? ["--component-set", i["componentSet"]] : [],
|
|
12297
|
+
...typeof i["figmaFile"] === "string" ? ["--figma-file", i["figmaFile"]] : []
|
|
12298
|
+
);
|
|
12257
12299
|
return argvOut;
|
|
12258
12300
|
}
|
|
12259
12301
|
},
|
|
@@ -14073,7 +14115,7 @@ function buildProgram() {
|
|
|
14073
14115
|
await runActivate2({ ...flags, serviceUrl: local["serviceUrl"] });
|
|
14074
14116
|
});
|
|
14075
14117
|
const record = program.command("record").description("Agent-driven recording protocol: plan the queue, get instructions, ingest verbatim envelopes, resume from disk.");
|
|
14076
|
-
record.command("plan").requiredOption("--set <dir>", "recording set directory").requiredOption("--component <name>", "component/system name").option("--metadata <file...>", "verbatim get_metadata envelope(s), optionally <file>@<frameId>").option("--metadata-raw-file <file>", "the get_metadata response TEXT exactly as received (single block); the CLI builds the envelope itself").option("--metadata-raw-parts-file <file>", "a JSON array of the get_metadata response blocks, each verbatim, in order (multi-block responses)").option("--default <axis=value...>", "explicit axis default, e.g. --default State=Rest (repeatable; persisted to the manifest; may re-plan an unrecorded set)").option("--component-set <name>", "when the metadata holds several component sets, record only this one (name = the set label in the plan error)").option("--sample", "cost sampling: anchor + one-factor + conflict crosses only (the FULL variant matrix is the default; sampling is blind to multi-axis interactions)").action(async (_o, cmd) => {
|
|
14118
|
+
record.command("plan").requiredOption("--set <dir>", "recording set directory").requiredOption("--component <name>", "component/system name").option("--metadata <file...>", "verbatim get_metadata envelope(s), optionally <file>@<frameId>").option("--metadata-raw-file <file>", "the get_metadata response TEXT exactly as received (single block); the CLI builds the envelope itself").option("--metadata-raw-parts-file <file>", "a JSON array of the get_metadata response blocks, each verbatim, in order (multi-block responses)").option("--default <axis=value...>", "explicit axis default, e.g. --default State=Rest (repeatable; persisted to the manifest; may re-plan an unrecorded set)").option("--component-set <name>", "when the metadata holds several component sets, record only this one (name = the set label in the plan error)").option("--sample", "cost sampling: anchor + one-factor + conflict crosses only (the FULL variant matrix is the default; sampling is blind to multi-axis interactions)").option("--figma-file <key>", "the Figma file key from the design URL (figma.com/design/<KEY>/\u2026) \u2014 recorded as the set's file identity for cross-bundle composition (ADR-013; fresh plans only, never backfilled)").action(async (_o, cmd) => {
|
|
14077
14119
|
const flags = globalFlags(cmd.parent.parent);
|
|
14078
14120
|
const local = cmd.opts();
|
|
14079
14121
|
const { runRecordPlan: runRecordPlan2 } = await Promise.resolve().then(() => (init_record(), record_exports));
|
|
@@ -14082,6 +14124,7 @@ function buildProgram() {
|
|
|
14082
14124
|
setDir: local["set"],
|
|
14083
14125
|
component: local["component"],
|
|
14084
14126
|
sample: local["sample"],
|
|
14127
|
+
...local["figmaFile"] !== void 0 ? { figmaFile: local["figmaFile"] } : {},
|
|
14085
14128
|
...local["metadata"] !== void 0 ? { metadataFiles: local["metadata"] } : {},
|
|
14086
14129
|
...local["metadataRawFile"] !== void 0 ? { metadataRawFile: local["metadataRawFile"] } : {},
|
|
14087
14130
|
...local["metadataRawPartsFile"] !== void 0 ? { metadataRawPartsFile: local["metadataRawPartsFile"] } : {},
|