skillscript-runtime 0.2.10 → 0.2.12
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 +54 -10
- package/dist/cli.js +13 -9
- package/dist/cli.js.map +1 -1
- package/dist/compile.d.ts +7 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +11 -2
- package/dist/compile.js.map +1 -1
- package/dist/help-content.d.ts.map +1 -1
- package/dist/help-content.js +135 -4
- package/dist/help-content.js.map +1 -1
- package/dist/lint.d.ts +10 -0
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +169 -22
- package/dist/lint.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +9 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +55 -4
- package/dist/parser.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +16 -2
- package/dist/runtime.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +30 -0
- package/dist/version.js.map +1 -0
- package/examples/hello.skill.provenance.json +1 -1
- package/package.json +1 -1
package/dist/help-content.js
CHANGED
|
@@ -264,6 +264,44 @@ Skill files open with \`# Key: value\` headers. Order isn't significant.
|
|
|
264
264
|
\`\`\`
|
|
265
265
|
|
|
266
266
|
Trigger sources today: \`cron\` (poll-based), \`session\` (\`start\` / \`end\` phases). Parse-only in v0.2: \`event\`, \`agent-event\`, \`file-watch\`, \`sensor\` (firing lands in v1.0).
|
|
267
|
+
|
|
268
|
+
## Ambient variables (auto-populated by the runtime)
|
|
269
|
+
|
|
270
|
+
The runtime injects these refs — don't declare them in \`# Vars:\` / \`# Requires:\`.
|
|
271
|
+
|
|
272
|
+
| Ref | Source | Notes |
|
|
273
|
+
|---|---|---|
|
|
274
|
+
| \`$(NOW)\` | runtime clock | ISO-8601 timestamp at op-dispatch time |
|
|
275
|
+
| \`$(USER)\` | invocation context | Identity passed via \`agentId\` / CLI user |
|
|
276
|
+
| \`$(SESSION_CONTEXT)\` | runtime session | Free-form session snapshot for cross-skill carry |
|
|
277
|
+
| \`$(TRIGGER_TYPE)\` | scheduler | \`cron\` / \`session\` / \`manual\` / \`agent-event\` |
|
|
278
|
+
| \`$(TRIGGER_PAYLOAD)\` | scheduler | JSON-serializable payload attached to the firing trigger |
|
|
279
|
+
| \`$(ERROR_CONTEXT)\` | runtime error handler | Inside \`else:\` and \`# OnError:\` only; \`.kind\` / \`.message\` / \`.target\` accessible |
|
|
280
|
+
|
|
281
|
+
\`EVENT.*\` auto-populates on cron-fired skills (v0.2.7 scheduler):
|
|
282
|
+
|
|
283
|
+
| Ref | Value |
|
|
284
|
+
|---|---|
|
|
285
|
+
| \`$(EVENT.fired_at)\` | epoch milliseconds |
|
|
286
|
+
| \`$(EVENT.fired_at_unix)\` | epoch seconds |
|
|
287
|
+
| \`$(EVENT.fired_at_plus_1h_unix)\` | \`fired_at_unix + 3600\` |
|
|
288
|
+
| \`$(EVENT.fired_at_plus_1d_unix)\` | \`fired_at_unix + 86_400\` |
|
|
289
|
+
| \`$(EVENT.fired_at_plus_7d_unix)\` | \`fired_at_unix + 604_800\` |
|
|
290
|
+
|
|
291
|
+
(v0.2.12 Bug 24 — \`EVENT.*\` was undocumented before this release.)
|
|
292
|
+
|
|
293
|
+
## Variable reference forms
|
|
294
|
+
|
|
295
|
+
\`\`\`
|
|
296
|
+
$(VAR) bare ref (any declared/output-bound/ambient name)
|
|
297
|
+
$(VAR.field) dotted field access on JSON-bound vars + ambient family
|
|
298
|
+
$(LIST.0) indexed access (v0.2.12 Bug 25 — was undocumented)
|
|
299
|
+
$(LIST.0.id) mixed indexed + field-access (chains arbitrarily deep)
|
|
300
|
+
$(VAR|filter) filter pipe (see \`help({topic: "ops"})\` for filter list)
|
|
301
|
+
$(VAR.field|filter) field-access then filter
|
|
302
|
+
\`\`\`
|
|
303
|
+
|
|
304
|
+
Unresolved refs: tier-1 \`undeclared-var\` at compile, \`UnresolvedVariableError\` at runtime.
|
|
267
305
|
`;
|
|
268
306
|
const EXAMPLES = `# Three canonical worked skills
|
|
269
307
|
|
|
@@ -335,6 +373,93 @@ default: route
|
|
|
335
373
|
\`\`\`
|
|
336
374
|
|
|
337
375
|
Demonstrates: \`~\` LocalModel op, named model selection, \`|trim\` filter on LLM output, ref-vs-literal comparison, agent delivery via \`prompt-context:\`, augmenting headers (\`# Delivery-context:\` + \`# Templates:\`).
|
|
376
|
+
|
|
377
|
+
## 4. Composition — orchestrator invoking child skills
|
|
378
|
+
|
|
379
|
+
\`\`\`
|
|
380
|
+
# Skill: morning-brief-orchestrator
|
|
381
|
+
# Description: Fan out to three child skills, gather their outputs into one brief.
|
|
382
|
+
# Status: Approved
|
|
383
|
+
# Vars: USER_NAME=Scott
|
|
384
|
+
|
|
385
|
+
gather:
|
|
386
|
+
$ execute_skill skill_name=calendar-today USER=$(USER_NAME) -> CAL (fallback: "(no calendar data)")
|
|
387
|
+
$ execute_skill skill_name=mailbox-triage USER=$(USER_NAME) -> MAIL (fallback: "(mailbox empty)")
|
|
388
|
+
$ execute_skill skill_name=weather-summary -> WX (fallback: "(weather unavailable)")
|
|
389
|
+
|
|
390
|
+
render: gather
|
|
391
|
+
! Good morning, $(USER_NAME). Today:
|
|
392
|
+
! • Calendar: $(CAL)
|
|
393
|
+
! • Mailbox: $(MAIL)
|
|
394
|
+
! • Weather: $(WX)
|
|
395
|
+
|
|
396
|
+
default: render
|
|
397
|
+
\`\`\`
|
|
398
|
+
|
|
399
|
+
Demonstrates: in-skill \`$ execute_skill\` composition (each child runs through the runtime under a depth-counted chain), per-call \`(fallback: ...)\` for resilience, kwarg forwarding (\`USER=$(USER_NAME)\`), \`->\` binding child output for downstream reference.
|
|
400
|
+
`;
|
|
401
|
+
const COMPOSITION = `# Composition
|
|
402
|
+
|
|
403
|
+
Skillscript has three composition primitives — all let one skill draw on another's output, with different semantics around when, where, and how the child runs.
|
|
404
|
+
|
|
405
|
+
## 1. \`& <skill-name>\` — data-skill inline (compile-time)
|
|
406
|
+
|
|
407
|
+
Inlines an *Approved data skill* into the host skill's compiled artifact at the call site. The data skill's body becomes part of the rendered prompt. Use for *static* knowledge or templated content (style guides, voice rules, runbooks).
|
|
408
|
+
|
|
409
|
+
\`\`\`
|
|
410
|
+
brief:
|
|
411
|
+
~ prompt="$(VOICE_RULES) Now write a one-line status:" model=qwen -> RESULT
|
|
412
|
+
& voice-rules
|
|
413
|
+
\`\`\`
|
|
414
|
+
|
|
415
|
+
- Resolved at \`compile()\` time — the data skill's \`content_hash\` is recorded in the host's provenance block.
|
|
416
|
+
- Provenance lets \`skillfile audit\` detect stale recompiles when a referenced data skill changes.
|
|
417
|
+
- The data skill must be marked \`# Skill-kind: data\` (or live in a path the SkillStore recognizes as data); otherwise it's treated as procedural and won't inline.
|
|
418
|
+
|
|
419
|
+
## 2. \`& invoke <skill-name>\` — runtime call (per-fire)
|
|
420
|
+
|
|
421
|
+
Calls a procedural skill at runtime. Each call goes through the runtime under a depth-counted chain (default limit 5) — same recursion guard as Style 3 below.
|
|
422
|
+
|
|
423
|
+
\`\`\`
|
|
424
|
+
escalate:
|
|
425
|
+
& invoke notify-oncall
|
|
426
|
+
\`\`\`
|
|
427
|
+
|
|
428
|
+
- Child skill's outputs flow into the parent's variable scope.
|
|
429
|
+
- Failures propagate as \`OpError\`s.
|
|
430
|
+
|
|
431
|
+
## 3. \`$ execute_skill skill_name="<child>" ...kwargs -> VAR\` — in-skill execute (per-fire)
|
|
432
|
+
|
|
433
|
+
The most general form: the host \`$\`-dispatches the literal tool name \`execute_skill\` (intercepted by the runtime, not sent to any MCP server). Same depth-counted chain as Style 2, plus full kwarg forwarding and \`-> VAR\` binding for downstream use.
|
|
434
|
+
|
|
435
|
+
\`\`\`
|
|
436
|
+
gather:
|
|
437
|
+
$ execute_skill skill_name="calendar-today" USER=$(USER_NAME) -> CAL (fallback: "(no calendar data)")
|
|
438
|
+
$ execute_skill skill_name="mailbox-triage" inputs={"USER": "$(USER_NAME)"} -> MAIL
|
|
439
|
+
\`\`\`
|
|
440
|
+
|
|
441
|
+
Two kwarg styles, both supported (v0.2.9 fix):
|
|
442
|
+
- **Bare kwargs** — \`USER=$(USER_NAME)\` natural skill grammar
|
|
443
|
+
- **\`inputs={...}\` JSON** — MCP-call parity, useful when forwarding many fields verbatim
|
|
444
|
+
|
|
445
|
+
The bound \`-> VAR\` carries the child's final emit through to the host's scope.
|
|
446
|
+
|
|
447
|
+
## Limits & lint signals
|
|
448
|
+
|
|
449
|
+
- **Recursion**: depth-5 chain by default (\`ExecuteSkillRecursionError\` if exceeded). Both \`& invoke\` and \`$ execute_skill\` share the counter.
|
|
450
|
+
- **Lint** (\`unknown-skill-reference\`, tier-1): \`& <name>\`, \`& invoke <name>\`, and \`$ execute_skill skill_name=<name>\` all validate the child skill exists in the SkillStore at compile time (v0.2.11 Bug 7 closed the \`$ execute_skill\` gap).
|
|
451
|
+
- **Lint** (\`disabled-skill-reference\`, tier-1): any composition primitive pointing at a \`# Status: Disabled\` skill blocks compile.
|
|
452
|
+
|
|
453
|
+
## When to use which
|
|
454
|
+
|
|
455
|
+
| Use case | Primitive |
|
|
456
|
+
|---|---|
|
|
457
|
+
| Static knowledge in a prompt | \`& <data-skill>\` |
|
|
458
|
+
| Fire-and-forget child call | \`& invoke <skill>\` |
|
|
459
|
+
| Child output bound into parent scope | \`$ execute_skill ... -> VAR\` |
|
|
460
|
+
| Parallel orchestrators (v0.3.0 candidate — not yet shipped) | parked |
|
|
461
|
+
|
|
462
|
+
See \`help({topic: "examples"})\` example 4 for a worked orchestrator skill.
|
|
338
463
|
`;
|
|
339
464
|
const CONNECTORS_PROLOGUE = `# Connectors
|
|
340
465
|
|
|
@@ -385,19 +510,22 @@ Three tiers per ERD §3:
|
|
|
385
510
|
- \`single-equals\` — \`if $(VAR) = "..."\` instead of \`==\` (specific diagnostic)
|
|
386
511
|
- \`indentation\` — tabs in indentation; mixed tabs/spaces
|
|
387
512
|
- \`reserved-keyword\` — variable/target/skill name collides with a reserved word
|
|
388
|
-
- \`unknown-skill-reference\` — \`&\`
|
|
389
|
-
- \`
|
|
513
|
+
- \`unknown-skill-reference\` — \`&\` or \`$ execute_skill\` references a skill not in the store (v0.2.11 Bug 7 extended to cover \`$ execute_skill\`)
|
|
514
|
+
- \`unknown-template-reference\` — \`# Templates: <name>\` references a skill not in the store (v0.2.12 Bug 17)
|
|
515
|
+
- \`disabled-skill-reference\` — \`&\` or \`$ execute_skill\` references a Disabled skill
|
|
390
516
|
- \`credential-in-args\` — op arg looks like a secret literal
|
|
391
517
|
- \`status-disabled\` — skill marked \`# Status: Disabled\`
|
|
392
518
|
- \`circular-dependency\` — dep cycle between targets
|
|
393
519
|
- \`missing-dependency\` — \`needs:\` references a target not declared
|
|
394
520
|
- \`missing-skillstore-for-data-ref\` — \`&\` op fires without a SkillStore wired
|
|
521
|
+
- \`unsafe-shell-disabled\` — \`@ unsafe\` declared but \`enableUnsafeShell: false\` (v0.2.11 Bug 5; fires only when caller passes the flag explicitly false)
|
|
395
522
|
|
|
396
523
|
## Tier-2 (warning)
|
|
397
524
|
|
|
398
525
|
- \`deprecated-question\` — bare \`?\` op (deprecated v1; compile-error in v1.x)
|
|
399
526
|
- \`unsafe-shell-ambiguous-subst\` — \`$(NAME)\` inside \`@ unsafe\` body that isn't a declared variable; collides with bash command-sub syntax
|
|
400
527
|
- \`unsafe-shell-op\` — \`@ unsafe\` op present; requires human review every time
|
|
528
|
+
- \`unknown-retrieval-arg\` — \`>\` op carries kwargs outside mode/query/limit/connector/fallback (v0.2.12 Bug 26)
|
|
401
529
|
- \`unconfirmed-mutation\` — \`$\` op invokes a tool whose name suggests mutation (write/update/delete) without a preceding \`??\` confirmation
|
|
402
530
|
- \`model-contention\` — async + sync ops on the same model serialize on a single runtime worker
|
|
403
531
|
- \`draft-with-trigger\` — \`# Status: Draft\` skill has \`# Triggers:\` declared; triggers won't fire until Approved
|
|
@@ -420,7 +548,7 @@ export function helpResponse(topic, runtimeVersion, registry) {
|
|
|
420
548
|
topic: null,
|
|
421
549
|
version: runtimeVersion,
|
|
422
550
|
content: QUICKSTART,
|
|
423
|
-
available_topics: ["ops", "frontmatter", "examples", "connectors", "lint-codes"],
|
|
551
|
+
available_topics: ["ops", "frontmatter", "examples", "composition", "connectors", "lint-codes"],
|
|
424
552
|
};
|
|
425
553
|
}
|
|
426
554
|
let content;
|
|
@@ -434,6 +562,9 @@ export function helpResponse(topic, runtimeVersion, registry) {
|
|
|
434
562
|
case "examples":
|
|
435
563
|
content = EXAMPLES;
|
|
436
564
|
break;
|
|
565
|
+
case "composition":
|
|
566
|
+
content = COMPOSITION;
|
|
567
|
+
break;
|
|
437
568
|
case "connectors":
|
|
438
569
|
content = renderConnectorsTopic(registry);
|
|
439
570
|
break;
|
|
@@ -441,7 +572,7 @@ export function helpResponse(topic, runtimeVersion, registry) {
|
|
|
441
572
|
content = LINT_CODES;
|
|
442
573
|
break;
|
|
443
574
|
default:
|
|
444
|
-
content = `# Unknown topic '${topic}'\n\nValid topics: ops, frontmatter, examples, connectors, lint-codes`;
|
|
575
|
+
content = `# Unknown topic '${topic}'\n\nValid topics: ops, frontmatter, examples, composition, connectors, lint-codes`;
|
|
445
576
|
}
|
|
446
577
|
return { topic, version: runtimeVersion, content };
|
|
447
578
|
}
|
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,mEAAmE;AACnE,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkGlB,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4GX,CAAC;AAEF,MAAM,WAAW,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
CHANGED
|
@@ -69,6 +69,15 @@ export interface LintOptions {
|
|
|
69
69
|
* preflight). Default `"api"`.
|
|
70
70
|
*/
|
|
71
71
|
callSite?: "cli" | "api" | "compile-preflight";
|
|
72
|
+
/**
|
|
73
|
+
* Runtime `enableUnsafeShell` flag, if known to the caller. When
|
|
74
|
+
* explicitly `false`, the `unsafe-shell-disabled` rule (v0.2.11 Bug 5)
|
|
75
|
+
* fires tier-1 on any `@ unsafe` op — the skill would refuse at
|
|
76
|
+
* runtime, and compile should surface that up-front. When `undefined`
|
|
77
|
+
* (caller doesn't know), only the standard tier-2 `unsafe-shell-op`
|
|
78
|
+
* warning fires.
|
|
79
|
+
*/
|
|
80
|
+
enableUnsafeShell?: boolean;
|
|
72
81
|
}
|
|
73
82
|
interface LintContext {
|
|
74
83
|
parsed: ParsedSkill;
|
|
@@ -78,6 +87,7 @@ interface LintContext {
|
|
|
78
87
|
skillStore: SkillStore | undefined;
|
|
79
88
|
hasSkillStore: boolean;
|
|
80
89
|
callSite: "cli" | "api" | "compile-preflight";
|
|
90
|
+
enableUnsafeShell: boolean | undefined;
|
|
81
91
|
}
|
|
82
92
|
export interface LintRule {
|
|
83
93
|
id: string;
|
package/dist/lint.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,WAAW,EAAgB,MAAM,aAAa,CAAC;AAEpE,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;
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,WAAW,EAAgB,MAAM,aAAa,CAAC;AAEpE,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;CAC7B;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,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;CACxC;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,CAiCrF;AAED,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,CAgC1E;AAED,6HAA6H;AAC7H,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAW3D;AAk6BD,mFAAmF;AACnF,wBAAgB,SAAS,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAElE"}
|
package/dist/lint.js
CHANGED
|
@@ -9,6 +9,7 @@ export async function lint(source, options) {
|
|
|
9
9
|
skillStore: options?.skillStore,
|
|
10
10
|
hasSkillStore: options?.skillStore !== undefined,
|
|
11
11
|
callSite: options?.callSite ?? "api",
|
|
12
|
+
enableUnsafeShell: options?.enableUnsafeShell,
|
|
12
13
|
};
|
|
13
14
|
const findings = [];
|
|
14
15
|
for (const rule of RULES) {
|
|
@@ -41,6 +42,7 @@ export function lintSync(source, options) {
|
|
|
41
42
|
skillStore: options?.skillStore,
|
|
42
43
|
hasSkillStore: options?.skillStore !== undefined,
|
|
43
44
|
callSite: options?.callSite ?? "api",
|
|
45
|
+
enableUnsafeShell: options?.enableUnsafeShell,
|
|
44
46
|
};
|
|
45
47
|
const findings = [];
|
|
46
48
|
for (const rule of RULES) {
|
|
@@ -364,20 +366,21 @@ const UNKNOWN_SKILL_REFERENCE = {
|
|
|
364
366
|
const findings = [];
|
|
365
367
|
const seen = new Set();
|
|
366
368
|
for (const [targetName, target] of ctx.parsed.targets) {
|
|
367
|
-
for (const
|
|
368
|
-
|
|
369
|
+
for (const ref of collectAmpRefsFromOps(target.ops)) {
|
|
370
|
+
const key = `${ref.via}:${ref.name}`;
|
|
371
|
+
if (seen.has(key))
|
|
369
372
|
continue;
|
|
370
|
-
seen.add(
|
|
373
|
+
seen.add(key);
|
|
371
374
|
try {
|
|
372
|
-
await ctx.skillStore.metadata(
|
|
375
|
+
await ctx.skillStore.metadata(ref.name);
|
|
373
376
|
}
|
|
374
377
|
catch {
|
|
375
378
|
findings.push({
|
|
376
379
|
rule: "unknown-skill-reference",
|
|
377
380
|
severity: "error",
|
|
378
|
-
message: `Skill '${targetName}' references skill '${
|
|
381
|
+
message: `Skill '${targetName}' references skill '${ref.name}' via \`${ref.via}\`, but the SkillStore has no skill by that name.`,
|
|
379
382
|
block: targetName,
|
|
380
|
-
extras: { referenced_skill:
|
|
383
|
+
extras: { referenced_skill: ref.name, via: ref.via },
|
|
381
384
|
});
|
|
382
385
|
}
|
|
383
386
|
}
|
|
@@ -385,6 +388,70 @@ const UNKNOWN_SKILL_REFERENCE = {
|
|
|
385
388
|
return findings;
|
|
386
389
|
},
|
|
387
390
|
};
|
|
391
|
+
// v0.2.12 Bug 26. Tier-2 warning when a `>` retrieval op carries kwargs
|
|
392
|
+
// outside the documented set. Cold author wrote `since=1h` (hallucinated
|
|
393
|
+
// time-window predicate) and the kwarg passed silently. The documented
|
|
394
|
+
// kwarg set is mode/query/limit/connector/fallback plus filter shapes
|
|
395
|
+
// the connector advertises via staticCapabilities (out of band here).
|
|
396
|
+
const KNOWN_RETRIEVAL_KWARGS = new Set(["mode", "query", "limit", "connector", "fallback"]);
|
|
397
|
+
const UNKNOWN_RETRIEVAL_ARG = {
|
|
398
|
+
id: "unknown-retrieval-arg",
|
|
399
|
+
severity: "warning",
|
|
400
|
+
description: "A `>` retrieval op carries a kwarg outside the documented set (mode/query/limit/connector/fallback).",
|
|
401
|
+
remediation: "Remove the kwarg, or check it against your MemoryStore connector's documentation — extras pass through to the connector but unrecognized ones often indicate hallucinated syntax.",
|
|
402
|
+
check: (ctx) => {
|
|
403
|
+
const findings = [];
|
|
404
|
+
for (const [targetName, target] of ctx.parsed.targets) {
|
|
405
|
+
walkOps(target.ops, (op) => {
|
|
406
|
+
if (op.kind !== ">")
|
|
407
|
+
return;
|
|
408
|
+
const extras = op.retrievalParams?.extra ?? {};
|
|
409
|
+
for (const k of Object.keys(extras)) {
|
|
410
|
+
if (KNOWN_RETRIEVAL_KWARGS.has(k))
|
|
411
|
+
continue;
|
|
412
|
+
findings.push({
|
|
413
|
+
rule: "unknown-retrieval-arg",
|
|
414
|
+
severity: "warning",
|
|
415
|
+
message: `\`>\` op in target '${targetName}' carries unknown kwarg '${k}'. Documented kwargs: ${Array.from(KNOWN_RETRIEVAL_KWARGS).join(", ")}. If '${k}' is a connector-specific filter, confirm it against the connector's docs.`,
|
|
416
|
+
block: targetName,
|
|
417
|
+
extras: { unknown_kwarg: k },
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
return findings;
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
// v0.2.12 Bug 17. `# Templates:` refs were not lint-validated despite
|
|
426
|
+
// `# OnError:` having compile-time validation (since v0.2.10). Tier-1
|
|
427
|
+
// because a missing template fails delivery at runtime.
|
|
428
|
+
const UNKNOWN_TEMPLATE_REFERENCE = {
|
|
429
|
+
id: "unknown-template-reference",
|
|
430
|
+
severity: "error",
|
|
431
|
+
description: "`# Templates: <name>` references a skill that's not present in the configured SkillStore.",
|
|
432
|
+
remediation: "Check the template name spelling, or store the missing template skill before referencing it. Templates resolve at delivery time; missing ones fail the agent delivery.",
|
|
433
|
+
check: async (ctx) => {
|
|
434
|
+
if (ctx.skillStore === undefined)
|
|
435
|
+
return [];
|
|
436
|
+
if (ctx.parsed.templates.length === 0)
|
|
437
|
+
return [];
|
|
438
|
+
const findings = [];
|
|
439
|
+
for (const name of ctx.parsed.templates) {
|
|
440
|
+
try {
|
|
441
|
+
await ctx.skillStore.metadata(name);
|
|
442
|
+
}
|
|
443
|
+
catch {
|
|
444
|
+
findings.push({
|
|
445
|
+
rule: "unknown-template-reference",
|
|
446
|
+
severity: "error",
|
|
447
|
+
message: `Skill references template '${name}' via \`# Templates:\`, but the SkillStore has no skill by that name.`,
|
|
448
|
+
extras: { referenced_skill: name },
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return findings;
|
|
453
|
+
},
|
|
454
|
+
};
|
|
388
455
|
const DISABLED_SKILL_REFERENCE = {
|
|
389
456
|
id: "disabled-skill-reference",
|
|
390
457
|
severity: "error",
|
|
@@ -396,19 +463,19 @@ const DISABLED_SKILL_REFERENCE = {
|
|
|
396
463
|
const findings = [];
|
|
397
464
|
const checked = new Set();
|
|
398
465
|
for (const [targetName, target] of ctx.parsed.targets) {
|
|
399
|
-
for (const
|
|
400
|
-
if (checked.has(
|
|
466
|
+
for (const ref of collectAmpRefsFromOps(target.ops)) {
|
|
467
|
+
if (checked.has(ref.name))
|
|
401
468
|
continue;
|
|
402
|
-
checked.add(
|
|
469
|
+
checked.add(ref.name);
|
|
403
470
|
try {
|
|
404
|
-
const meta = await ctx.skillStore.metadata(
|
|
471
|
+
const meta = await ctx.skillStore.metadata(ref.name);
|
|
405
472
|
if (meta.status === "Disabled") {
|
|
406
473
|
findings.push({
|
|
407
474
|
rule: "disabled-skill-reference",
|
|
408
475
|
severity: "error",
|
|
409
|
-
message: `Skill '${targetName}' references '${
|
|
476
|
+
message: `Skill '${targetName}' references '${ref.name}' via \`${ref.via}\` which is disabled.`,
|
|
410
477
|
block: targetName,
|
|
411
|
-
extras: { referenced_skill:
|
|
478
|
+
extras: { referenced_skill: ref.name, via: ref.via, target_status: meta.status },
|
|
412
479
|
});
|
|
413
480
|
}
|
|
414
481
|
}
|
|
@@ -627,6 +694,19 @@ const UNSAFE_SHELL_AMBIGUOUS_SUBST = {
|
|
|
627
694
|
const trimmed = inner.trim();
|
|
628
695
|
if (/^[A-Za-z_]\w*$/.test(trimmed) && declared.has(trimmed))
|
|
629
696
|
continue;
|
|
697
|
+
// v0.2.11 Bug 4: dotted refs (EVENT.fired_at_unix, MEMORY.x,
|
|
698
|
+
// <target>.output) are runtime ambient/output families — same
|
|
699
|
+
// dotted-passthrough heuristic as `undeclared-var`. The
|
|
700
|
+
// unsafe-shell warning was telling cold authors to rewrite
|
|
701
|
+
// `$(EVENT.fired_at_unix)` as `$$(EVENT.fired_at_unix)` (bash
|
|
702
|
+
// command-sub), which would just try to execute "EVENT...".
|
|
703
|
+
if (trimmed.includes("."))
|
|
704
|
+
continue;
|
|
705
|
+
// v0.2.11 Bug 4: bare ambient refs (NOW, USER, ERROR_CONTEXT,
|
|
706
|
+
// SESSION_CONTEXT, TRIGGER_TYPE, TRIGGER_PAYLOAD) also pass —
|
|
707
|
+
// runtime injects them, author doesn't declare.
|
|
708
|
+
if (AMBIENT_VARS.includes(trimmed))
|
|
709
|
+
continue;
|
|
630
710
|
if (reported.has(inner))
|
|
631
711
|
continue;
|
|
632
712
|
reported.add(inner);
|
|
@@ -665,8 +745,55 @@ const UNSAFE_SHELL_OP = {
|
|
|
665
745
|
return findings;
|
|
666
746
|
},
|
|
667
747
|
};
|
|
668
|
-
/**
|
|
669
|
-
|
|
748
|
+
/**
|
|
749
|
+
* v0.2.11 Bug 5. Tier-1 escalation of the unsafe-shell signal — only
|
|
750
|
+
* fires when the caller passed `enableUnsafeShell: false` explicitly.
|
|
751
|
+
* Without that knowledge (the field is undefined), this rule stays
|
|
752
|
+
* silent and the tier-2 `unsafe-shell-op` warning is the only signal.
|
|
753
|
+
*
|
|
754
|
+
* When the runtime is known-disabled, every `@ unsafe` op is a guaranteed
|
|
755
|
+
* runtime refusal (`UnsafeShellDisabledError`). Surfacing that at compile
|
|
756
|
+
* time instead of letting the skill compile clean and then fail at first
|
|
757
|
+
* fire avoids the "compiles clean but won't run" gap Perry's harness
|
|
758
|
+
* surfaced (memory `b6176e02`).
|
|
759
|
+
*/
|
|
760
|
+
const UNSAFE_SHELL_DISABLED = {
|
|
761
|
+
id: "unsafe-shell-disabled",
|
|
762
|
+
severity: "error",
|
|
763
|
+
description: "Skill uses `@ unsafe`, but the runtime was configured with `enableUnsafeShell: false`. The op will refuse at first fire.",
|
|
764
|
+
remediation: "Either set `enableUnsafeShell: true` on the runtime (after reviewing the shell content), or refactor the `@ unsafe` op to use the structured `@ <binary> <args>` form (sandboxed, no bash).",
|
|
765
|
+
check: (ctx) => {
|
|
766
|
+
if (ctx.enableUnsafeShell !== false)
|
|
767
|
+
return [];
|
|
768
|
+
const findings = [];
|
|
769
|
+
for (const [targetName, target] of ctx.parsed.targets) {
|
|
770
|
+
walkOps(target.ops, (op) => {
|
|
771
|
+
if (op.kind === "@" && op.policy === "unsafe") {
|
|
772
|
+
findings.push({
|
|
773
|
+
rule: "unsafe-shell-disabled",
|
|
774
|
+
severity: "error",
|
|
775
|
+
message: `\`@ unsafe\` op in target '${targetName}' would refuse at runtime: \`enableUnsafeShell\` is false. Command: '${op.body.slice(0, 60)}${op.body.length > 60 ? "..." : ""}'`,
|
|
776
|
+
block: targetName,
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
return findings;
|
|
782
|
+
},
|
|
783
|
+
};
|
|
784
|
+
/**
|
|
785
|
+
* Tool-name patterns that strongly suggest mutating operations.
|
|
786
|
+
* Conservative — false positives are tolerable for warnings; false
|
|
787
|
+
* negatives are dangerous.
|
|
788
|
+
*
|
|
789
|
+
* v0.2.11 Bug 6: extended with archive_/prune_/deploy_/expire_/
|
|
790
|
+
* consolidate_/purge_/reset_/rotate_/move_/rename_/drop_/truncate_/
|
|
791
|
+
* upsert_/overwrite_/clear_/wipe_/finalize_ — Perry's wild-and-crazy
|
|
792
|
+
* harness surfaced a cluster of mutating tools that the original
|
|
793
|
+
* write/update/delete/etc. set didn't catch (`archive_old_threads`,
|
|
794
|
+
* `prune_threads`, `deploy_release`, `dangerous-cleanup`'s `expire_*`).
|
|
795
|
+
*/
|
|
796
|
+
const MUTATING_TOOL_PATTERN = /^(?:write_|update_|delete_|remove_|set_|create_|insert_|put_|patch_|destroy_|archive_|prune_|deploy_|expire_|consolidate_|purge_|reset_|rotate_|move_|rename_|drop_|truncate_|upsert_|overwrite_|clear_|wipe_|finalize_).*/;
|
|
670
797
|
const UNCONFIRMED_MUTATION = {
|
|
671
798
|
id: "unconfirmed-mutation",
|
|
672
799
|
severity: "warning",
|
|
@@ -756,19 +883,19 @@ const REFERENCE_TO_DISABLED_SKILL = {
|
|
|
756
883
|
const findings = [];
|
|
757
884
|
const checked = new Set();
|
|
758
885
|
for (const [targetName, target] of ctx.parsed.targets) {
|
|
759
|
-
for (const
|
|
760
|
-
if (checked.has(
|
|
886
|
+
for (const ref of collectAmpRefsFromOps(target.ops)) {
|
|
887
|
+
if (checked.has(ref.name))
|
|
761
888
|
continue;
|
|
762
|
-
checked.add(
|
|
889
|
+
checked.add(ref.name);
|
|
763
890
|
try {
|
|
764
|
-
const meta = await ctx.skillStore.metadata(
|
|
891
|
+
const meta = await ctx.skillStore.metadata(ref.name);
|
|
765
892
|
if (meta.status === "Disabled") {
|
|
766
893
|
findings.push({
|
|
767
894
|
rule: "reference-to-disabled-skill",
|
|
768
895
|
severity: "warning",
|
|
769
|
-
message: `Target '${targetName}' references '${
|
|
896
|
+
message: `Target '${targetName}' references '${ref.name}' via \`${ref.via}\` which is disabled.`,
|
|
770
897
|
block: targetName,
|
|
771
|
-
extras: { referenced_skill:
|
|
898
|
+
extras: { referenced_skill: ref.name, via: ref.via },
|
|
772
899
|
});
|
|
773
900
|
}
|
|
774
901
|
}
|
|
@@ -872,6 +999,8 @@ const RULES = [
|
|
|
872
999
|
INDENTATION,
|
|
873
1000
|
RESERVED_KEYWORD,
|
|
874
1001
|
UNKNOWN_SKILL_REFERENCE,
|
|
1002
|
+
UNKNOWN_TEMPLATE_REFERENCE,
|
|
1003
|
+
UNKNOWN_RETRIEVAL_ARG,
|
|
875
1004
|
DISABLED_SKILL_REFERENCE,
|
|
876
1005
|
CREDENTIAL_IN_ARGS,
|
|
877
1006
|
STATUS_DISABLED,
|
|
@@ -882,6 +1011,7 @@ const RULES = [
|
|
|
882
1011
|
DEPRECATED_QUESTION,
|
|
883
1012
|
UNSAFE_SHELL_AMBIGUOUS_SUBST,
|
|
884
1013
|
UNSAFE_SHELL_OP,
|
|
1014
|
+
UNSAFE_SHELL_DISABLED,
|
|
885
1015
|
UNCONFIRMED_MUTATION,
|
|
886
1016
|
MODEL_CONTENTION,
|
|
887
1017
|
DRAFT_WITH_TRIGGER,
|
|
@@ -911,10 +1041,27 @@ function walkOps(ops, visit) {
|
|
|
911
1041
|
}
|
|
912
1042
|
}
|
|
913
1043
|
function collectAmpRefsFromOps(ops) {
|
|
914
|
-
const out =
|
|
1044
|
+
const out = [];
|
|
1045
|
+
const seen = new Set();
|
|
1046
|
+
const emit = (name, via) => {
|
|
1047
|
+
const key = `${via}:${name}`;
|
|
1048
|
+
if (seen.has(key))
|
|
1049
|
+
return;
|
|
1050
|
+
seen.add(key);
|
|
1051
|
+
out.push({ name, via });
|
|
1052
|
+
};
|
|
915
1053
|
walkOps(ops, (op) => {
|
|
916
1054
|
if (op.kind === "&" && op.ampParams !== undefined)
|
|
917
|
-
|
|
1055
|
+
emit(op.ampParams.skillName, "&");
|
|
1056
|
+
// v0.2.11 Bug 7: $ execute_skill is also a composition primitive.
|
|
1057
|
+
if (op.kind === "$" && /^execute_skill\b/.test(op.body)) {
|
|
1058
|
+
const m = /\bskill_name\s*=\s*(?:"([^"]+)"|'([^']+)'|([A-Za-z_][\w-]*))/.exec(op.body);
|
|
1059
|
+
if (m !== null) {
|
|
1060
|
+
const name = m[1] ?? m[2] ?? m[3];
|
|
1061
|
+
if (name !== undefined && name !== "")
|
|
1062
|
+
emit(name, "$ execute_skill");
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
918
1065
|
});
|
|
919
1066
|
return out;
|
|
920
1067
|
}
|