@tendrilapp/cli 0.1.27 → 0.1.29
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 +50 -15
- package/dist/tendril-mcp.js +13 -5
- package/dist/tendril.js +1033 -476
- package/package.json +1 -1
package/dist/SKILL.md
CHANGED
|
@@ -28,16 +28,40 @@ settings file the host merges — the project's
|
|
|
28
28
|
`.claude/settings.local.json` or `.claude/settings.json`, or the
|
|
29
29
|
user's `~/.claude/settings.json` — contains tendril MCP entries
|
|
30
30
|
(plugin installs use `mcp__plugin_tendril_tendril__*`; direct
|
|
31
|
-
`claude mcp add` installs use `mcp__<server-name>__*`)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
`claude mcp add` installs use `mcp__<server-name>__*`) AND shell-
|
|
32
|
+
surface entries (`Bash(ls:*)`-style prefixes plus `Write`/`Edit`)
|
|
33
|
+
AND Figma entries under the prefix THIS session's Figma tools
|
|
34
|
+
actually carry — take a Figma tool you can see (e.g. get_metadata)
|
|
35
|
+
and check its full `mcp__…` name against the allowlist; entries
|
|
36
|
+
under a different server's prefix are dead and DO NOT count (a
|
|
37
|
+
measured session held six such entries while every Figma call
|
|
38
|
+
prompted).
|
|
39
|
+
THE MCP LIST ALONE IS NOT "PERMISSIONS ARE FINE": a run is mostly
|
|
40
|
+
shell — mkdir, evidence reads, log writes, the printed npx commands —
|
|
41
|
+
and a measured session whose every MCP call was covered still put
|
|
42
|
+
~300 shell decisions to the user because this check certified only
|
|
43
|
+
the MCP half. If either half is missing, BEFORE the first recording
|
|
44
|
+
call, tell the user one approval can replace every pipeline prompt
|
|
45
|
+
and offer `tendril_permissions` with `write: true` — it merges the
|
|
46
|
+
per-tool allowlist PLUS the run's shell surface and project-scoped
|
|
47
|
+
Write/Edit (with deny guards so that grant can never touch
|
|
48
|
+
`./.claude/**` or `./.git/**`) into the project's
|
|
49
|
+
settings.local.json (idempotent, touches nothing else). PREFIXES:
|
|
50
|
+
pass `figmaPrefix` (and `tendrilPrefix` for non-plugin installs)
|
|
51
|
+
spelled exactly as THIS session names those tools — the part before
|
|
52
|
+
`__get_metadata` — whenever they differ from the plugin defaults; a
|
|
53
|
+
measured figma-remote session got six entries that could never
|
|
54
|
+
match because the write assumed the plugin shape. These are
|
|
55
|
+
CONVENIENCE grants, not a security boundary — the command's output
|
|
56
|
+
names what they trade (read verbs read any file without prompting;
|
|
57
|
+
host Bash patterns are best-effort prefix matches; the CLI
|
|
58
|
+
subcommand grants carry the CLI's own write surface). RELAY that
|
|
59
|
+
note to the user with the offer, never soften it, and say BOTH that
|
|
60
|
+
a reload is required AND that the current session keeps prompting
|
|
61
|
+
until then — the savings land next session; that is expected, not a
|
|
62
|
+
failure. Offer ONCE per session; never run it unoffered (it edits
|
|
63
|
+
the user's settings), and if declined, proceed without mentioning
|
|
64
|
+
it again.
|
|
41
65
|
|
|
42
66
|
Long generator/score waits: silence is not a health signal, and POLL
|
|
43
67
|
cadence is not RELAY cadence (run 13: rounds landed 6–11 minutes apart,
|
|
@@ -171,11 +195,13 @@ Batch runs (several components in one session):
|
|
|
171
195
|
Figma MCP calls in protocol order — get_metadata, then
|
|
172
196
|
get_design_context (excludeScreenshot=true), then get_screenshot —
|
|
173
197
|
and then ONE `tendril_record_ingest_rep` carrying all three:
|
|
174
|
-
metadata and context response text passed VERBATIM —
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
198
|
+
metadata and context response text passed VERBATIM — responses
|
|
199
|
+
often arrive as MULTIPLE output blocks (block counts vary BY
|
|
200
|
+
TRANSPORT: the desktop server has been measured at 2-4 blocks per
|
|
201
|
+
response, the remote server at 1-2 — never treat any count as a
|
|
202
|
+
sanity check), so `metadataParts`/`contextParts` (every block in
|
|
203
|
+
order, never hand-joined) is the normal path; `metadata`/`context`
|
|
204
|
+
only for a genuinely single-block response — plus the screenshot
|
|
179
205
|
`screenshotUrl` — no files
|
|
180
206
|
to write, no envelope to build, and never download the image
|
|
181
207
|
yourself. Every ingest response carries `next` (never call
|
|
@@ -278,6 +304,15 @@ Batch runs (several components in one session):
|
|
|
278
304
|
no prices or percentages (they go stale). Non-interactive runs
|
|
279
305
|
pick the balanced tier and state the reason in the report. Always
|
|
280
306
|
pass the choice via --host/--model (self-reported provenance).
|
|
307
|
+
CONSENT GATES AUTO-RESOLVED IN A NON-INTERACTIVE RUN — the model
|
|
308
|
+
pick, the parallel-recording decision — must open the FINAL REPORT,
|
|
309
|
+
first lines, not sit in a log: the user learns what was decided for
|
|
310
|
+
them before they read anything else. (Measured: an autonomy setting
|
|
311
|
+
converted both gates into buried deviations while the user sat
|
|
312
|
+
present and wanted to be asked. The non-interactive branch is for
|
|
313
|
+
genuinely headless runs; it cannot tell "nobody is there" from "the
|
|
314
|
+
harness said nobody is there", so it must at least say what it did,
|
|
315
|
+
loudly and first.)
|
|
281
316
|
Weak models produce honest sub-bar reports, never false passes.
|
|
282
317
|
6. Tell the user roughly what a run costs them: organism-scale
|
|
283
318
|
components have measured 0.3–0.7M tokens of their plan.
|
package/dist/tendril-mcp.js
CHANGED
|
@@ -66,11 +66,19 @@ var TOOLS = [
|
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
68
|
name: "tendril_permissions",
|
|
69
|
-
description: "Install the Claude Code permission allowlist for the Tendril pipeline (write: true \u2014 merges per-tool entries into the project's .claude/settings.local.json, idempotent, never touches other
|
|
69
|
+
description: "Install the Claude Code permission allowlist for the Tendril pipeline (write: true \u2014 merges the MCP per-tool entries, the run's shell surface, and project-scoped Write/Edit with deny guards for ./.claude and ./.git into the project's .claude/settings.local.json, idempotent, never touches other keys), or list the entries without writing. The shell/Write grants are CONVENIENCE, not a security boundary \u2014 the output's note names exactly what they trade; RELAY it with the offer. OFFER THIS AT PIPELINE START whenever NO merged Claude settings file (project .claude/settings.local.json or .claude/settings.json, or user ~/.claude/settings.json) contains tendril MCP entries \u2014 plugin installs use mcp__plugin_tendril_tendril__*, direct claude-mcp-add installs use mcp__<server>__* \u2014 when this session's tool names differ from the plugin defaults, pass figmaPrefix/tendrilPrefix with the prefixes you actually see, or the written entries never match. A FILE check, never prompt-watching \u2014 agents cannot observe permission prompts. ONE approval here replaces a prompt per pipeline call. Never run it unoffered; the user must reload the session for new settings to apply \u2014 say so.",
|
|
70
70
|
schema: z.object({
|
|
71
|
-
write: z.boolean().optional().describe("true = install into .claude/settings.local.json (the point of this tool); false/absent = just return the entries")
|
|
71
|
+
write: z.boolean().optional().describe("true = install into .claude/settings.local.json (the point of this tool); false/absent = just return the entries"),
|
|
72
|
+
figmaPrefix: z.string().optional().describe("The Figma server's entry prefix AS THIS SESSION NAMES ITS TOOLS \u2014 the part before __get_metadata (e.g. mcp__figma-remote, mcp__plugin_figma_figma). Pass it whenever the session's Figma tools are not mcp__plugin_figma_figma__* \u2014 entries written under the wrong prefix never match anything (measured: six dead entries in a figma-remote session)."),
|
|
73
|
+
tendrilPrefix: z.string().optional().describe("Same for the tendril server when this session's tendril tools are not mcp__plugin_tendril_tendril__* (e.g. mcp__tendril for claude mcp add installs).")
|
|
72
74
|
}),
|
|
73
|
-
argv: (i) => [
|
|
75
|
+
argv: (i) => [
|
|
76
|
+
"permissions",
|
|
77
|
+
"--claude",
|
|
78
|
+
...i["write"] === true ? ["--write"] : [],
|
|
79
|
+
...typeof i["figmaPrefix"] === "string" ? ["--figma-prefix", i["figmaPrefix"]] : [],
|
|
80
|
+
...typeof i["tendrilPrefix"] === "string" ? ["--tendril-prefix", i["tendrilPrefix"]] : []
|
|
81
|
+
]
|
|
74
82
|
},
|
|
75
83
|
{
|
|
76
84
|
name: "tendril_doctor",
|
|
@@ -195,7 +203,7 @@ var TOOLS = [
|
|
|
195
203
|
{
|
|
196
204
|
name: "tendril_record_status",
|
|
197
205
|
annotations: { readOnlyHint: true },
|
|
198
|
-
description: "Recording-set completeness: per-rep recorded/missing tools.",
|
|
206
|
+
description: "Recording-set completeness: per-rep recorded/missing tools, files that exist but are unusable (invalid \u2014 re-record those), and whether the set-level token map is recorded. `complete` means USABLE by the next pipeline step, including the set-level get_variable_defs.",
|
|
199
207
|
schema: z.object({ setDir: str("recording set directory") }),
|
|
200
208
|
argv: (i) => ["record", "status", "--set", i["setDir"]]
|
|
201
209
|
},
|
|
@@ -226,7 +234,7 @@ var TOOLS = [
|
|
|
226
234
|
},
|
|
227
235
|
{
|
|
228
236
|
name: "tendril_engine_score",
|
|
229
|
-
description: "AGENT-HARNESS engine, step 2 (the oracle): scores a candidate bundle directory against recorded truth \u2014 per-config pixels, behaviors,
|
|
237
|
+
description: "AGENT-HARNESS engine, step 2 (the oracle): scores a candidate bundle directory against recorded truth \u2014 per-config pixels, behaviors, state parity (recording-selected \u2014 a bundle cannot unschedule it) \u2014 and returns feedback plus evidence artifacts. Iterate until allPass or two non-improving rounds. Only THIS tool's output counts as a score; never claim numbers yourself.",
|
|
230
238
|
schema: z.object({
|
|
231
239
|
taskOrSet: str("reference task name or recording-set directory"),
|
|
232
240
|
candidateDir: str("directory containing the proposed bundle files"),
|