skillscript-runtime 0.17.2 → 0.17.4
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/bootstrap.d.ts +18 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +1 -0
- package/dist/bootstrap.js.map +1 -1
- package/dist/cli.js +42 -6
- package/dist/cli.js.map +1 -1
- package/dist/composition.d.ts.map +1 -1
- package/dist/composition.js +33 -2
- package/dist/composition.js.map +1 -1
- package/dist/dotenv-loader.d.ts +29 -0
- package/dist/dotenv-loader.d.ts.map +1 -0
- package/dist/dotenv-loader.js +86 -0
- package/dist/dotenv-loader.js.map +1 -0
- package/dist/help-content.d.ts.map +1 -1
- package/dist/help-content.js +33 -4
- package/dist/help-content.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +172 -0
- package/dist/lint.js.map +1 -1
- package/dist/parser.d.ts +15 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +32 -0
- package/dist/parser.js.map +1 -1
- package/dist/runtime-config.d.ts +10 -0
- package/dist/runtime-config.d.ts.map +1 -1
- package/dist/runtime-config.js +8 -0
- package/dist/runtime-config.js.map +1 -1
- package/docs/configuration.md +75 -0
- package/docs/language-reference.md +70 -13
- package/examples/skillscripts/hello-world.skill.provenance.json +1 -1
- package/package.json +1 -1
- package/scaffold/.env.example +89 -0
package/dist/help-content.js
CHANGED
|
@@ -260,13 +260,15 @@ inline(skill="common-prelude")
|
|
|
260
260
|
|
|
261
261
|
### \`execute_skill(name="...", ...kwargs) -> R\` — runtime skill composition
|
|
262
262
|
|
|
263
|
-
Invokes another stored skill end-to-end against the runtime's connectors. Returns the
|
|
263
|
+
Invokes another stored skill end-to-end against the runtime's connectors. Returns the child's execution record — \`outputs\` + \`transcript\` + \`errors\` + \`target_order\` + (filtered) \`final_vars\`. Access via \`\${R.outputs.text}\`, \`\${R.transcript}\`, \`\${R.final_vars.FIELD}\`, etc.
|
|
264
264
|
|
|
265
265
|
\`\`\`
|
|
266
266
|
execute_skill(name="extract-json-number", JSON_BLOB="\${RAW}", FIELD_PATH="total_count") -> RESULT
|
|
267
|
-
emit(text="Extracted: \${RESULT.
|
|
267
|
+
emit(text="Extracted: \${RESULT.outputs.text}")
|
|
268
268
|
\`\`\`
|
|
269
269
|
|
|
270
|
+
**v0.17.3 — Returns filter.** \`R.final_vars\` is filtered to the called skill's \`# Returns: X, Y, Z\` declaration. Skills without \`# Returns:\` declared export nothing from \`final_vars\` — the caller sees \`outputs\` + \`transcript\` + execution metadata, but no internal vars. Internal scratch (large JSON, intermediate computations, debug values) stays local to the child and never serializes into the caller's \`R\`. To expose a value for caller consumption, declare it in the called skill's \`# Returns:\` header.
|
|
271
|
+
|
|
270
272
|
\`name\` is the canonical kwarg, aligning with \`skill_read({name})\` / \`skill_write({name})\` / \`skill_status({name})\`. \`skill_name\` is accepted as a silent back-compat alias.
|
|
271
273
|
|
|
272
274
|
## Class 3: External MCP dispatch
|
|
@@ -402,7 +404,8 @@ Skill files open with \`# Key: value\` headers. Order isn't significant.
|
|
|
402
404
|
|
|
403
405
|
- \`# Description: <prose>\` — human-readable explanation; surfaces in dashboards.
|
|
404
406
|
- \`# Type: procedural | data\` — \`procedural\` (default) for runtime-fired skills; \`data\` for compile-time-inlined fragments referenced by \`inline(skill="...")\`.
|
|
405
|
-
- \`# Vars: NAME=default, OTHER\` — declared variables. \`NAME=default\` provides a default; bare \`NAME\` is required at invocation.
|
|
407
|
+
- \`# Vars: NAME=default, OTHER\` — declared variables. \`NAME=default\` provides a default; bare \`NAME\` is required at invocation. Quoted defaults (\`NAME="hello world"\`) strip one matched layer of surrounding quotes at parse time — quoted-spaced values bind correctly; bare values bind unchanged.
|
|
408
|
+
- \`# Returns: X, Y, Z\` — declared export surface for \`execute_skill\` composition. Names that propagate from this skill's \`final_vars\` into the caller's bound \`R\`. Internal scratch vars NOT listed here stay local — never serialized into the caller's result. Skills without \`# Returns:\` export nothing from \`final_vars\` (outputs + transcript + metadata still flow). Symmetric with \`# Vars:\` (input surface ↔ output surface).
|
|
406
409
|
- \`# Triggers: cron: 0 9 * * *, session: start\` — autonomous-dispatch sources. Comma-separated entries split by source-keyword boundary; cron expressions with commas (\`30,45 9 * * 1-5\`) parse correctly.
|
|
407
410
|
- \`# Output: text | agent: <name> | template: <name> | file: path | none\` — output routing. Five kinds, all substrate-neutral. **Two substrate-neutral lifecycle hooks**: \`agent: <name>\` routes via AgentConnector as augment-kind delivery; \`template: <name>\` routes as template-kind delivery (receiving agent executes the rendered playbook). Both default to **joined emissions string** (the \`emit(text=...)\` lines concatenated with newlines). \`text\` / \`file:\` default to the **last-bound variable value** (structured), falling back to the emissions array when no var was bound. If your skill emits multiple lines and a downstream consumer only sees the final tool output via \`outputs.text\`, that's the structured-default behavior — use \`# Output: agent: <name>\` (or another text-coerced kind) to publish the joined emissions instead. **For substrate-specific delivery destinations** (Slack, WhatsApp, Discord, pagerduty, custom dashboards, etc.) — that's contract-between-the-skill-and-the-substrate territory, downstream of the language. Two paths: (1) \`$ <connector>.<tool> ...\` inside the skill body to dispatch through an adopter-wired MCP connector, or (2) deliver via \`agent: <name>\` to an agent whose AgentConnector decides how to surface the result.
|
|
408
411
|
- \`# OnError: <fallback-skill-name>\` — error-handler skill invoked when an op fails and no target-level \`else:\` catches.
|
|
@@ -701,7 +704,33 @@ Two kwarg-forwarding styles, both supported:
|
|
|
701
704
|
- **Bare kwargs** — \`USER="\${USER_NAME}"\` natural skill grammar
|
|
702
705
|
- **\`inputs={...}\` JSON** — useful when forwarding many fields verbatim
|
|
703
706
|
|
|
704
|
-
The bound \`-> R\` carries the child's
|
|
707
|
+
The bound \`-> R\` carries the child's execution record into the host's scope:
|
|
708
|
+
- \`\${R.outputs.text}\` — the joined emission stream (the canonical accessor, what 100% of composers reach for)
|
|
709
|
+
- \`\${R.transcript}\` — array of individual emit lines
|
|
710
|
+
- \`\${R.final_vars.FIELD}\` — the child's declared exports (see \`# Returns:\` below)
|
|
711
|
+
- \`\${R.errors}\`, \`\${R.target_order}\` — execution metadata
|
|
712
|
+
|
|
713
|
+
**Declaring what gets exported (v0.17.3).** The child skill controls what's visible to the caller via its \`# Returns: X, Y, Z\` frontmatter header. Internal scratch (large JSON, intermediate computations) stays local; only declared names propagate into \`R.final_vars\`. Skills without \`# Returns:\` export nothing from \`final_vars\` — outputs + transcript + metadata still flow.
|
|
714
|
+
|
|
715
|
+
\`\`\`
|
|
716
|
+
# Skill: get-weather
|
|
717
|
+
# Vars: LOCATION=Valdese
|
|
718
|
+
# Returns: SUMMARY, TEMP_F
|
|
719
|
+
|
|
720
|
+
fetch:
|
|
721
|
+
shell(command="curl -s 'wttr.in/\${LOCATION|url}?format=j1'") -> RAW
|
|
722
|
+
$ json_parse \${RAW} -> PARSED
|
|
723
|
+
|
|
724
|
+
shape: fetch
|
|
725
|
+
$set TEMP_F = \${PARSED.current_condition.0.temp_F}
|
|
726
|
+
$set SUMMARY = "\${LOCATION}: \${TEMP_F}°F"
|
|
727
|
+
emit(text="\${SUMMARY}")
|
|
728
|
+
default: shape
|
|
729
|
+
\`\`\`
|
|
730
|
+
|
|
731
|
+
Caller binding \`-> R\` sees \`R.final_vars = {SUMMARY, TEMP_F}\` — NOT \`RAW\` or \`PARSED\` (internal scratch, filtered out by the Returns surface). Closes the "skills are functions; declare what you return" contract: internal state stays internal.
|
|
732
|
+
|
|
733
|
+
Lint \`unknown-returns-ref\` (tier-1) catches names declared in \`# Returns:\` that aren't bound anywhere in the skill body.
|
|
705
734
|
|
|
706
735
|
## Limits & lint signals
|
|
707
736
|
|
package/dist/help-content.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help-content.js","sourceRoot":"","sources":["../src/help-content.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,kEAAkE;AAClE,qEAAqE;AACrE,2BAA2B;AAC3B,EAAE;AACF,kBAAkB;AAClB,0EAA0E;AAC1E,+DAA+D;AAC/D,uCAAuC;AACvC,kFAAkF;AAClF,kFAAkF;AAClF,uDAAuD;AACvD,EAAE;AACF,uEAAuE;AACvE,yDAAyD;AAIzD,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+HlB,CAAC;AAEF,MAAM,GAAG,GAAG
|
|
1
|
+
{"version":3,"file":"help-content.js","sourceRoot":"","sources":["../src/help-content.ts"],"names":[],"mappings":"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"}
|
package/dist/lint.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,WAAW,EAAgB,MAAM,aAAa,CAAC;AAGzF,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,kBAAkB,IAAI,kBAAkB,CAAA;KAAE,CAAC,CAAC;IAC9D,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,mBAAmB,CAAC;IAC/C;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B;;;;;;;OAOG;IACH,wBAAwB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACjD;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC;;;;;;;;;;;;;;;OAeG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB;sFACkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,KAAK,CAAC;QAAE,kBAAkB,IAAI,kBAAkB,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAC9E,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;IACnC,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,mBAAmB,CAAC;IAC9C,iBAAiB,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACxC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,wBAAwB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChD,mBAAmB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC1C,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACxC,oBAAoB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3C,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B;;;;;;OAMG;IACH,uBAAuB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAChE,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,wBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA6CrF;AAED,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,CAyC1E;AAED,6HAA6H;AAC7H,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAW3D;AAqhFD,mFAAmF;AACnF,wBAAgB,SAAS,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAElE"}
|
package/dist/lint.js
CHANGED
|
@@ -295,6 +295,55 @@ const UNDECLARED_VAR = {
|
|
|
295
295
|
return findings;
|
|
296
296
|
},
|
|
297
297
|
};
|
|
298
|
+
// v0.17.3 — `# Returns: X, Y` where X (or Y) isn't bound anywhere in the
|
|
299
|
+
// skill body. Tier-1: an undeclared export is structurally broken — the
|
|
300
|
+
// skill claims to return something it never sets. Same shape as
|
|
301
|
+
// `undeclared-var` but checked against the export-surface side. Per
|
|
302
|
+
// Perry's `1ea3d625` Finding 2 + skillscript's `6fb6ac1c` empirical
|
|
303
|
+
// pre-flight; the lint enforces the function-signature contract at
|
|
304
|
+
// author time so the runtime-side Returns-filter doesn't silently
|
|
305
|
+
// produce an absent value.
|
|
306
|
+
const UNKNOWN_RETURNS_REF = {
|
|
307
|
+
id: "unknown-returns-ref",
|
|
308
|
+
severity: "error",
|
|
309
|
+
description: "A name in `# Returns:` isn't bound anywhere in the skill body — not declared in `# Vars:`/`# Requires:`, not output-bound by any op, not a foreach iterator. The skill declares an export it never produces.",
|
|
310
|
+
remediation: "Bind the variable with `$set`, `-> VAR` on an op, a foreach iterator, or declare it in `# Vars:`/`# Requires:`. Or remove the name from `# Returns:` if it shouldn't be exported.",
|
|
311
|
+
check: (ctx) => {
|
|
312
|
+
if (ctx.parsed.returns.length === 0)
|
|
313
|
+
return [];
|
|
314
|
+
const declared = new Set();
|
|
315
|
+
for (const v of ctx.parsed.vars)
|
|
316
|
+
declared.add(v.name);
|
|
317
|
+
for (const r of ctx.parsed.requires)
|
|
318
|
+
declared.add(r.target);
|
|
319
|
+
for (const target of ctx.parsed.targets.values()) {
|
|
320
|
+
const collect = (op) => {
|
|
321
|
+
if (op.setName !== undefined)
|
|
322
|
+
declared.add(op.setName);
|
|
323
|
+
if (op.outputVar !== undefined)
|
|
324
|
+
declared.add(op.outputVar);
|
|
325
|
+
if (op.foreachIter !== undefined)
|
|
326
|
+
declared.add(op.foreachIter);
|
|
327
|
+
};
|
|
328
|
+
walkOps(target.ops, collect);
|
|
329
|
+
if (target.elseBlock !== undefined)
|
|
330
|
+
walkOps(target.elseBlock, collect);
|
|
331
|
+
}
|
|
332
|
+
const findings = [];
|
|
333
|
+
for (const name of ctx.parsed.returns) {
|
|
334
|
+
if (declared.has(name))
|
|
335
|
+
continue;
|
|
336
|
+
findings.push({
|
|
337
|
+
rule: "unknown-returns-ref",
|
|
338
|
+
severity: "error",
|
|
339
|
+
message: `\`# Returns: ${name}\` — '${name}' isn't bound anywhere in the skill body. Bind it with \`$set ${name} = ...\` / \`-> ${name}\` on an op / a foreach iterator / \`# Vars: ${name}=...\`, or remove it from \`# Returns:\`.`,
|
|
340
|
+
block: "(frontmatter)",
|
|
341
|
+
extras: { referenced_name: name },
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
return findings;
|
|
345
|
+
},
|
|
346
|
+
};
|
|
298
347
|
const UNKNOWN_FILTER = {
|
|
299
348
|
id: "unknown-filter",
|
|
300
349
|
severity: "error",
|
|
@@ -1880,6 +1929,127 @@ const SET_JSON_LITERAL_ADVISORY = {
|
|
|
1880
1929
|
// substitution and advise. False positives possible (if a user binds a
|
|
1881
1930
|
// non-composition var named with `.transcript`), but the suggestion
|
|
1882
1931
|
// reads as a helpful nudge either way.
|
|
1932
|
+
// v0.17.4 — `${R.final_vars.X}` where R was bound by `$ execute_skill
|
|
1933
|
+
// skill_name="<child>" ... -> R` and `X` isn't in `<child>`'s declared
|
|
1934
|
+
// `# Returns:`. The runtime filter drops the value silently — the
|
|
1935
|
+
// caller gets `undefined`/empty at substitution time. Lint catches the
|
|
1936
|
+
// asymmetry between caller's reach and child's declared export.
|
|
1937
|
+
// Sibling to v0.17.3's `unknown-returns-ref` (tier-1) on the
|
|
1938
|
+
// declaration side; this rule is tier-2 advisory on the consumer side.
|
|
1939
|
+
//
|
|
1940
|
+
// Forward-reference deferred: if the called skill isn't in the
|
|
1941
|
+
// SkillStore at lint time, skip — `unknown-skill-reference` (tier-2)
|
|
1942
|
+
// already flags the missing-ref case. Once the called skill exists,
|
|
1943
|
+
// this rule fires the next time the host is linted.
|
|
1944
|
+
const UNEXPORTED_FINAL_VAR_ACCESS = {
|
|
1945
|
+
id: "unexported-final-var-access",
|
|
1946
|
+
severity: "warning",
|
|
1947
|
+
description: "A `${R.final_vars.X}` reference accesses a name not declared in the called skill's `# Returns:` header. The runtime filter drops the value; the substitution renders empty.",
|
|
1948
|
+
remediation: "Add `X` to the called skill's `# Returns:` header (to export it), or remove the access (if you meant `${R.outputs.text}` or another always-exported field).",
|
|
1949
|
+
check: async (ctx) => {
|
|
1950
|
+
if (ctx.skillStore === undefined)
|
|
1951
|
+
return [];
|
|
1952
|
+
// Step 1: build a map of execute_skill bindings — { boundVar: calledSkillName }
|
|
1953
|
+
const bindings = new Map();
|
|
1954
|
+
for (const target of ctx.parsed.targets.values()) {
|
|
1955
|
+
walkOps(target.ops, (op) => {
|
|
1956
|
+
if (op.kind !== "$" || op.outputVar === undefined)
|
|
1957
|
+
return;
|
|
1958
|
+
if (!/^execute_skill\b/.test(op.body))
|
|
1959
|
+
return;
|
|
1960
|
+
// v0.15.2 — accept either `name` or `skill_name` (back-compat alias).
|
|
1961
|
+
const m = /\b(?:skill_name|name)\s*=\s*(?:"([^"]+)"|'([^']+)'|([A-Za-z_][\w-]*))/.exec(op.body);
|
|
1962
|
+
if (m === null)
|
|
1963
|
+
return;
|
|
1964
|
+
const skillName = m[1] ?? m[2] ?? m[3];
|
|
1965
|
+
if (skillName === undefined || skillName === "")
|
|
1966
|
+
return;
|
|
1967
|
+
bindings.set(op.outputVar, skillName);
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
if (bindings.size === 0)
|
|
1971
|
+
return [];
|
|
1972
|
+
// Step 2: load each referenced skill's parsed.returns. Cache the
|
|
1973
|
+
// lookup so multiple references to the same child resolve once.
|
|
1974
|
+
const returnsCache = new Map();
|
|
1975
|
+
const loadReturns = async (skillName) => {
|
|
1976
|
+
if (returnsCache.has(skillName))
|
|
1977
|
+
return returnsCache.get(skillName);
|
|
1978
|
+
let result;
|
|
1979
|
+
try {
|
|
1980
|
+
const loaded = await ctx.skillStore.load(skillName);
|
|
1981
|
+
const parsed = parse(loaded.source);
|
|
1982
|
+
result = new Set(parsed.returns);
|
|
1983
|
+
}
|
|
1984
|
+
catch {
|
|
1985
|
+
result = null; // missing skill — forward-reference deferred to unknown-skill-reference
|
|
1986
|
+
}
|
|
1987
|
+
returnsCache.set(skillName, result);
|
|
1988
|
+
return result;
|
|
1989
|
+
};
|
|
1990
|
+
// Step 3: walk ops looking for `${R.final_vars.X}` patterns where R
|
|
1991
|
+
// is a known execute_skill binding. Check X against the called
|
|
1992
|
+
// skill's returns.
|
|
1993
|
+
const findings = [];
|
|
1994
|
+
const reported = new Set();
|
|
1995
|
+
// Match both `$(R.final_vars.X...)` and `${R.final_vars.X...}` forms.
|
|
1996
|
+
// Capture the binding-var and the first field-name after final_vars.
|
|
1997
|
+
const re = /\$[({]([A-Za-z_]\w*)\.final_vars\.([A-Za-z_]\w*)/g;
|
|
1998
|
+
for (const [targetName, target] of ctx.parsed.targets) {
|
|
1999
|
+
const scanString = async (s) => {
|
|
2000
|
+
let m;
|
|
2001
|
+
const localMatches = [];
|
|
2002
|
+
while ((m = re.exec(s)) !== null) {
|
|
2003
|
+
localMatches.push({ bindVar: m[1], fieldName: m[2], raw: m[0] });
|
|
2004
|
+
}
|
|
2005
|
+
for (const { bindVar, fieldName, raw } of localMatches) {
|
|
2006
|
+
if (!bindings.has(bindVar))
|
|
2007
|
+
continue;
|
|
2008
|
+
const calledSkill = bindings.get(bindVar);
|
|
2009
|
+
const returns = await loadReturns(calledSkill);
|
|
2010
|
+
if (returns === null)
|
|
2011
|
+
continue; // forward-ref, deferred
|
|
2012
|
+
if (returns.has(fieldName))
|
|
2013
|
+
continue;
|
|
2014
|
+
const key = `${targetName}:${raw}`;
|
|
2015
|
+
if (reported.has(key))
|
|
2016
|
+
continue;
|
|
2017
|
+
reported.add(key);
|
|
2018
|
+
const declared = returns.size === 0 ? "(none — skill has no `# Returns:` header)" : `[${Array.from(returns).join(", ")}]`;
|
|
2019
|
+
findings.push({
|
|
2020
|
+
rule: "unexported-final-var-access",
|
|
2021
|
+
severity: "warning",
|
|
2022
|
+
message: `\`${raw}...}\` in target '${targetName}' accesses '${fieldName}' on the result of \`execute_skill\` to '${calledSkill}', but '${fieldName}' isn't in that skill's \`# Returns:\` (declared: ${declared}). The runtime filter drops it; substitution renders empty. Add '${fieldName}' to '${calledSkill}' \`# Returns:\` or use \`\${${bindVar}.outputs.text}\` for the always-exported emission stream.`,
|
|
2023
|
+
block: targetName,
|
|
2024
|
+
extras: { bind_var: bindVar, called_skill: calledSkill, field: fieldName, declared_returns: Array.from(returns) },
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
};
|
|
2028
|
+
const collect = async (op) => {
|
|
2029
|
+
if (op.body !== undefined)
|
|
2030
|
+
await scanString(op.body);
|
|
2031
|
+
if (op.setValue !== undefined)
|
|
2032
|
+
await scanString(op.setValue);
|
|
2033
|
+
};
|
|
2034
|
+
const walkAsync = async (ops) => {
|
|
2035
|
+
for (const op of ops) {
|
|
2036
|
+
await collect(op);
|
|
2037
|
+
if (op.foreachBody !== undefined)
|
|
2038
|
+
await walkAsync(op.foreachBody);
|
|
2039
|
+
if (op.ifBranches !== undefined)
|
|
2040
|
+
for (const b of op.ifBranches)
|
|
2041
|
+
await walkAsync(b.body);
|
|
2042
|
+
if (op.ifElseBody !== undefined)
|
|
2043
|
+
await walkAsync(op.ifElseBody);
|
|
2044
|
+
}
|
|
2045
|
+
};
|
|
2046
|
+
await walkAsync(target.ops);
|
|
2047
|
+
if (target.elseBlock !== undefined)
|
|
2048
|
+
await walkAsync(target.elseBlock);
|
|
2049
|
+
}
|
|
2050
|
+
return findings;
|
|
2051
|
+
},
|
|
2052
|
+
};
|
|
1883
2053
|
const TRANSCRIPT_FOOTGUN = {
|
|
1884
2054
|
id: "transcript-footgun",
|
|
1885
2055
|
severity: "warning",
|
|
@@ -2545,6 +2715,7 @@ const RULES = [
|
|
|
2545
2715
|
ORPHAN_TARGET,
|
|
2546
2716
|
UNKNOWN_CAPABILITY,
|
|
2547
2717
|
UNDECLARED_VAR,
|
|
2718
|
+
UNKNOWN_RETURNS_REF,
|
|
2548
2719
|
UNKNOWN_FILTER,
|
|
2549
2720
|
MALFORMED_OP_GRAMMAR,
|
|
2550
2721
|
INVALID_CONDITIONAL_SYNTAX,
|
|
@@ -2586,6 +2757,7 @@ const RULES = [
|
|
|
2586
2757
|
DEPRECATED_ADDRESSED_TO,
|
|
2587
2758
|
LEGACY_FRONTMATTER_HEADER,
|
|
2588
2759
|
TRANSCRIPT_FOOTGUN,
|
|
2760
|
+
UNEXPORTED_FINAL_VAR_ACCESS,
|
|
2589
2761
|
SET_JSON_LITERAL_ADVISORY,
|
|
2590
2762
|
SKILL_NAME_COLLISION,
|
|
2591
2763
|
UNKNOWN_LLM_MODEL,
|